<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>marcduerst.com — Notes on Code &amp; Cloud</title><description>Articles on software architecture, cloud, and engineering by Marc Dürst.</description><link>https://marcduerst.com/</link><language>en-us</language><atom:link href="https://marcduerst.com/rss.xml" rel="self" type="application/rss+xml"/><item><title>AI-Assisted Software Product Development — A Practical Field Report</title><link>https://marcduerst.com/blog/ai-assisted-software-product-development/</link><guid isPermaLink="true">https://marcduerst.com/blog/ai-assisted-software-product-development/</guid><description>Practical insights from building a SaaS product almost entirely with AI assistance — from specs and refinement to coding, security reviews, and operations debugging. Plus thoughts on what this means for our industry.</description><pubDate>Sun, 05 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2026/collaborative-coding-with-ai-assistant.png&quot; alt=&quot;Collaborative coding with AI assistant&quot;&gt;&lt;/p&gt;
&lt;p&gt;Since the beginning of 2026 I’ve been doing more and more AI-assisted software development. The models reached a level where they are genuinely helpful — not perfect, but useful enough to change how I work every day. To explore not just the coding assistance but the &lt;em&gt;full software product development cycle&lt;/em&gt;, I started building &lt;a href=&quot;https://feldnah.ch&quot;&gt;feldnah.ch&lt;/a&gt; — a SaaS application. From idea to business concept, requirements engineering, planning, refinement, development, deployment, security reviews, and marketing. I wanted to understand how future software product teams might look and act.&lt;/p&gt;
&lt;p&gt;The following are my findings so far.&lt;/p&gt;
&lt;h2 id=&quot;spec-driven-development-is-back&quot;&gt;Spec-Driven Development is Back&lt;/h2&gt;
&lt;p&gt;If you’ve been in the industry long enough, you remember spec-driven development. BDD with Gherkin, SpecFlow, custom step definitions — it was a lot of ceremony. The idea was right but the tooling overhead killed it for many teams.&lt;/p&gt;
&lt;p&gt;With AI-assisted development, spec-driven is making a comeback — but in a much more practical form:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;You don’t need full specs.&lt;/strong&gt; Write down the important points as bullet points. Then iterate with the AI on the final specification. The AI fills in the gaps you didn’t think of, and you correct what it got wrong.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Natural language, not DSLs.&lt;/strong&gt; Specs are written in Markdown — no Gherkin syntax, no custom parsers, no SpecFlow bindings. GitHub, GitLab, and any editor renders them nicely as formatted documents.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No implementation from scratch.&lt;/strong&gt; You don’t need to type every line of code. The spec becomes the input for AI-assisted implementation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a fundamental shift: specs are no longer just documentation that gets outdated. They become the &lt;em&gt;living input&lt;/em&gt; for your AI-powered development workflow.&lt;/p&gt;
&lt;h2 id=&quot;build-a-machine-readable-briefing&quot;&gt;Build a Machine-Readable Briefing&lt;/h2&gt;
&lt;p&gt;One of the most impactful things you can do is build a structured context that AI tools can read whenever they work on your project. I think of it as a “briefing” — everything the AI needs to know about your product, your standards, and your way of working.&lt;/p&gt;
&lt;p&gt;This includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Business domain knowledge&lt;/strong&gt; — what the product does and why&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Corporate design&lt;/strong&gt; — tone of voice, visual language, color schemes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User interaction guidelines&lt;/strong&gt; — how your app should behave&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Technology stack and priorities&lt;/strong&gt; — what you use and what you prefer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coding and pattern guidelines&lt;/strong&gt; — e.g., “we do vertical slices combined with CQRS”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Keep it concise.&lt;/strong&gt; Don’t be verbose — the AI reads it every time. Every unnecessary sentence burns tokens and dilutes the signal.&lt;/p&gt;
&lt;h3 id=&quot;a-folder-structure-that-works&quot;&gt;A Folder Structure That Works&lt;/h3&gt;
&lt;p&gt;Here’s the structure I’m currently using. It’s not set in stone — it evolves with every repo I work on. But it’s a solid starting point:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;specs/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── concept.md                   # Core business concepts, USPs, principles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── architecture.md              # Technical architecture, tech stack, patterns&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── ubiquitous_language.md       # Shared terminology (DDD-inspired)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── userinterface_guidelines.md  # UI/UX rules and guidelines&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── backlog.md                   # Human-written ideas and backlog items&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── flows/                       # Important user flows&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── stories/                     # One markdown file per story&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── _template.md             # Template for new stories&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   └── done/                    # Archive of completed stories&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;└── adrs/                        # Architecture decision records&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    └── _template.md             # Template for new ADRs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your &lt;code&gt;README.md&lt;/code&gt; should be a concise summary of the most important things — think of it as the landing page of your repo. It’s the first thing people see when they browse your repository or open a PR review on GitHub. Place links to the files in &lt;code&gt;/specs&lt;/code&gt; for deeper reading.&lt;/p&gt;
&lt;p&gt;Then configure your AI tools (like &lt;code&gt;CLAUDE.md&lt;/code&gt; for Claude Code) to reference &lt;code&gt;README.md&lt;/code&gt; and the &lt;code&gt;/specs&lt;/code&gt; folder as context.&lt;/p&gt;
&lt;h2 id=&quot;make-the-ai-assistant-yours&quot;&gt;Make the AI Assistant Yours&lt;/h2&gt;
&lt;p&gt;You can brief the AI on how to behave and respond to you. A colleague told me he configured his Claude to yell back at him or respond in Swiss German when in “yelling mode.” This gives the AI a more personal touch — it makes those long AI-assisted sessions feel less like commanding a dumb machine all day.&lt;/p&gt;
&lt;p&gt;I personally switched back to a default conversational mode. I found myself reading responses seriously until I realized the AI was just joking — it slightly increased my mental load. But try it. Some people love it.&lt;/p&gt;
&lt;h2 id=&quot;my-refinement-and-implementation-process&quot;&gt;My Refinement and Implementation Process&lt;/h2&gt;
&lt;p&gt;This is where it gets practical. Here’s my actual workflow for going from idea to production. It works very well as a solo developer, though it would need adaptation for larger teams.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Capture the idea&lt;/strong&gt; — Write rough ideas as headings in &lt;code&gt;backlog.md&lt;/code&gt; with bullet points. Quick, unstructured, just getting thoughts down.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generate the story&lt;/strong&gt; — Prompt: &lt;em&gt;“Write a story for backlog item X.”&lt;/em&gt; The AI uses &lt;code&gt;stories/_template.md&lt;/code&gt;, respects my specs, ADRs, and past stories. The result is usually more detailed than what a human team would write — and that’s intentional. A good story is key for a good implementation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review and iterate the story&lt;/strong&gt; — Review, edit manually or prompt the AI to fix specific aspects. When solid, commit &lt;code&gt;backlog.md&lt;/code&gt; and all story files into Git — they’re part of the codebase.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implement&lt;/strong&gt; — Prompt: &lt;em&gt;“Story X looks good, implement it.”&lt;/em&gt; The AI reads the story, specs, existing code, and writes the implementation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review and test&lt;/strong&gt; — Quick code review of what changed, focusing on the important parts and unit test coverage. Then manually test every user-facing change. No exceptions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Iterate&lt;/strong&gt; — Using AI prompts or, rarely, by coding manually.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Document decisions&lt;/strong&gt; — If architectural decisions were made, have the AI write a new ADR. If specs need updating, tell the AI — or it does it automatically because it’s part of my story template.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Close and ship&lt;/strong&gt; — Prompt: &lt;em&gt;“Close story X.”&lt;/em&gt; This writes the changelog, updates the story status to &lt;em&gt;done&lt;/em&gt;, removes it from the backlog, and moves the story file to &lt;code&gt;/specs/stories/done&lt;/code&gt;. Then &lt;em&gt;“commit and push”&lt;/em&gt; triggers CI/CD and the feature is live.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;a-note-on-code-reviews&quot;&gt;A Note on Code Reviews&lt;/h3&gt;
&lt;p&gt;How I review AI-generated code evolved over time. In the beginning I reviewed every single line. Now I focus on the big picture and the critical parts. I don’t spend much time reviewing CSS changes or straightforward UI code.&lt;/p&gt;
&lt;p&gt;I also adjusted my mindset on code quality: not every line needs to be diamond-level from day one. Core logic and persistence absolutely should be. But the UI layer can have some redundancy — I can refactor it all at once later using AI. This would have been heresy for me two years ago.&lt;/p&gt;
&lt;h2 id=&quot;beyond-coding-ai-in-the-product-lifecycle&quot;&gt;Beyond Coding: AI in the Product Lifecycle&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2026/sdlc.png&quot; alt=&quot;Human-AI collaboration across the software development lifecycle&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;ai-assisted-market-analytics&quot;&gt;AI-Assisted Market Analytics&lt;/h3&gt;
&lt;p&gt;I use AI to query various aspects of the business around my product. The specs provide context — they’re like a persisted memory for the AI. I always ask for sources to validate business numbers. If your market analysis is based on speculation, your product will hit the wall.&lt;/p&gt;
&lt;h3 id=&quot;ai-assisted-security-reviews&quot;&gt;AI-Assisted Security Reviews&lt;/h3&gt;
&lt;p&gt;AI-assisted security reviews are remarkably effective when you have good specs. The AI understands what’s important for this specific product and at what security level you need to operate.&lt;/p&gt;
&lt;p&gt;I had a genuine wow moment when I asked the AI to calculate worst-case scenarios for my SaaS app. &lt;em&gt;“What happens if my app gets DDoS’ed? What will be the costs?”&lt;/em&gt; Claude Code produced a comprehensive analysis with serious calculations for various scenarios. I was already in good shape (it’s not my first cloud app), but it found interesting gaps that I then closed. The cost calculations were surprisingly accurate — I double-checked them against actual cloud pricing.&lt;/p&gt;
&lt;p&gt;Always verify security findings. But as a starting point, it’s incredibly efficient.&lt;/p&gt;
&lt;h3 id=&quot;ai-assisted-operations-debugging&quot;&gt;AI-Assisted Operations Debugging&lt;/h3&gt;
&lt;p&gt;In my day job at Switzerland’s biggest e-commerce site, I started using AI for production issue debugging. My reasoning: if there’s one thing these models are good at, it’s finding patterns and correlations in large amounts of data.&lt;/p&gt;
&lt;p&gt;I connected various data sources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Git&lt;/strong&gt; via CLI — for looking up implementations including infrastructure-as-code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub&lt;/strong&gt; via &lt;code&gt;gh&lt;/code&gt; CLI — for analyzing deployments to production&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Datadog&lt;/strong&gt; via MCP — for standard and custom metrics&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Google Cloud&lt;/strong&gt; via &lt;code&gt;gcloud&lt;/code&gt; CLI — for querying real infrastructure and GCP logs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also wrote a &lt;code&gt;docs/monitoring.md&lt;/code&gt; with all monitoring links: dashboards, metrics, notebooks, alerts. Then I created a &lt;em&gt;skill&lt;/em&gt; (a reusable prompt) that tells the AI how to drill down production issues, references the monitoring doc and specs, and outputs a readable Markdown report.&lt;/p&gt;
&lt;p&gt;I iterate on that report like a living document — it becomes the persisted context for the investigation.&lt;/p&gt;
&lt;p&gt;What genuinely surprised me was the patterns the AI found — correlations I wouldn’t have spotted as quickly myself. It also figured out creative ways to query the information it needed, adapting well to our specific tooling and data structures. When standard queries weren’t enough, it wrote Python scripts on the fly for more complex data gathering and analysis.&lt;/p&gt;
&lt;p&gt;That said, it’s critical to double-check every finding. You need the expertise yourself — you cannot blindly rely on AI for production debugging. I always include something like &lt;em&gt;“no speculations, only hard and validated facts, double-check numbers if possible”&lt;/em&gt; in my prompts. Without that, the AI tends to fill gaps with plausible-sounding guesses — which is the last thing you want in a production incident.&lt;/p&gt;
&lt;h3 id=&quot;ai-assisted-cloud-cost-debugging&quot;&gt;AI-Assisted Cloud Cost Debugging&lt;/h3&gt;
&lt;p&gt;When cloud costs spike unexpectedly, you want to know why fast. This can be straightforward or extremely complex and time-consuming.&lt;/p&gt;
&lt;p&gt;I use the same approach as operations debugging, but with an additional data source: cost reports (via &lt;code&gt;gcloud&lt;/code&gt; CLI or CSV exports from the GCP console).&lt;/p&gt;
&lt;p&gt;I was genuinely surprised at how well Claude Code correlated cost increases with operational events and traced complex, accumulated effects along a timeline. It can reduce a massive amount of time and effort that would otherwise go into manually cross-referencing billing data, metrics, and deployment events. But you need cloud cost expertise yourself to quickly judge when the AI is going off track — and it will, especially with complex multi-service billing.&lt;/p&gt;
&lt;h2 id=&quot;more-ideas-for-ai-assistance&quot;&gt;More Ideas for AI Assistance&lt;/h2&gt;
&lt;p&gt;The list of things AI can assist with keeps growing. Here are some I’ve explored or seen in practice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Implement UIs from Figma designs&lt;/strong&gt; — AI reads existing Figma documents via MCP and generates the frontend code to match&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generate social media content&lt;/strong&gt; like Instagram reels using Canva MCP&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web UI prototypes&lt;/strong&gt; using Gemini’s web preview capabilities&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UX documentation&lt;/strong&gt; — tone of voice, color schemas, personas&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AppStore screenshot updates&lt;/strong&gt; — stitching new screenshots into marketing images&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Release notes and changelogs&lt;/strong&gt; — generated from commit history and stories, adapted to the target audience (users, not developers)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dependency updates&lt;/strong&gt; — update libraries and frameworks including migrating breaking changes across repositories&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Concept drafts&lt;/strong&gt; from Confluence and Jira using connectors/MCP&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UX analysis&lt;/strong&gt; — AI reviews your interface and suggests improvements&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO analysis and optimization&lt;/strong&gt; right in the code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Social media post optimization&lt;/strong&gt; — tailored per platform (Instagram is different from LinkedIn)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automated user testing&lt;/strong&gt; — define different personas and their behavior, then let AI test your software automatically with each of them&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regional research&lt;/strong&gt; — e.g., “find all farmers with farm shops within 20km that have online ordering, and compare their features”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Translation automation&lt;/strong&gt; in web and native apps&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full native app releases&lt;/strong&gt; — build, translate, publish to Apple, generate “what’s new” tailored to your audience in all languages, and more. Goes way beyond static CI/CD pipelines because it can adapt&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;thoughts-on-what-this-means&quot;&gt;Thoughts on What This Means&lt;/h2&gt;
&lt;p&gt;I want to close with some broader reflections. These are things I think about a lot, and I don’t have all the answers.&lt;/p&gt;
&lt;h3 id=&quot;the-industry-cant-ignore-this&quot;&gt;The Industry Can’t Ignore This&lt;/h3&gt;
&lt;p&gt;AI tooling has reached a level where the software industry cannot afford to look away. Companies that don’t adapt will face serious competitive disadvantages. The same goes for professionals — dismissive hate-speech about AI tools won’t age well. The pragmatic approach is to understand what these tools can and can’t do, and use them where they genuinely help.&lt;/p&gt;
&lt;h3 id=&quot;quality-still-requires-expertise&quot;&gt;Quality Still Requires Expertise&lt;/h3&gt;
&lt;p&gt;To get professional-quality results, &lt;em&gt;you&lt;/em&gt; need to have the expertise. AI amplifies what you bring to the table — if you bring deep knowledge, you get excellent results. If you bring nothing, you get plausible-looking garbage. The human in the loop is not optional. It’s the quality gate.&lt;/p&gt;
&lt;h3 id=&quot;the-junior-developer-question&quot;&gt;The Junior Developer Question&lt;/h3&gt;
&lt;p&gt;This one keeps me up at night. AI handles most of the basic tasks that juniors traditionally learn on. But to work efficiently with AI, you need decent domain &lt;em&gt;and&lt;/em&gt; technical knowledge. How do you build that knowledge if AI is doing the doing? Our industry needs to think seriously about mentorship, learning paths, and what “junior” even means in an AI-assisted world.&lt;/p&gt;
&lt;h3 id=&quot;organizational-change-beyond-code&quot;&gt;Organizational Change Beyond Code&lt;/h3&gt;
&lt;p&gt;This isn’t just about AI-assisted coding. Workflows, processes, and even team structures will change. Product owners will refine differently. QA will test differently. The roles of architect, developer, and operator are blurring. We’re looking at a fundamental shift in how software product teams are composed and how they collaborate.&lt;/p&gt;
&lt;p&gt;I’m joining a temporary cross-functional team at Digitec Galaxus that’s exploring exactly these new ways of working. I’m looking forward to learning a lot about future team dynamics and workflows — and I’ll keep you posted.&lt;/p&gt;
&lt;h3 id=&quot;the-pace-and-the-uncertainty&quot;&gt;The Pace and the Uncertainty&lt;/h3&gt;
&lt;p&gt;I can’t imagine what will be possible in just six months. The pace of improvement is breathtaking. But I suspect it will slow down at some point as things saturate. Every major AI company is running deep financial losses. If this technology persists — and I believe it will — it will likely become more expensive.&lt;/p&gt;
&lt;h3 id=&quot;the-environmental-cost&quot;&gt;The Environmental Cost&lt;/h3&gt;
&lt;p&gt;The environmental impact of this way of working is significant, and I’m not a fan of this side of the medal. Training and running these models consumes enormous amounts of energy. As an industry, we need to ask: how do we make this sustainable? I don’t have a good answer yet, but ignoring the question isn’t one either.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;This post reflects my experience as of early 2026. The tooling and best practices are evolving rapidly. What works today might look different in a few months — but the underlying principles of good specs, human expertise, and critical thinking will remain.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title>Integrating Machine Learning — A Software Engineer&apos;s Guide</title><link>https://marcduerst.com/blog/machine-learning-from-a-software-engineer-perspective/</link><guid isPermaLink="true">https://marcduerst.com/blog/machine-learning-from-a-software-engineer-perspective/</guid><description>What software engineers need to know about collaborating with data scientists, integrating ML models into production, and the offline vs. online divide.</description><pubDate>Fri, 03 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is not a post about how to train models or write Python notebooks. It’s about what I’ve learned as a software engineer working alongside data scientists — how to collaborate effectively, what to watch out for when integrating ML into production, and why the offline/online distinction matters more than most people think.&lt;/p&gt;
&lt;p&gt;But lets start with some basics…&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-data-scientist&quot;&gt;What is a Data Scientist&lt;/h2&gt;
&lt;p&gt;There are two roles sound similar for software engineer: &lt;em&gt;Data Analyst&lt;/em&gt; and &lt;em&gt;Data Scientist&lt;/em&gt;. The two roles are often confused, but from an engineering perspective they have very different needs and outputs. Think of it in software terms:&lt;/p&gt;
&lt;h3 id=&quot;data-analysts&quot;&gt;Data Analysts&lt;/h3&gt;
&lt;p&gt;Data analysts are like your monitoring and debugging experts — but for the business. They look at what &lt;em&gt;happened&lt;/em&gt; and try to explain &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;They query collected data, build dashboards, spot anomalies, and present findings to stakeholders. Their output is insights and recommendations, not code that runs in production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In engineering terms:&lt;/strong&gt; if a data analyst were a developer, they’d be the one reading logs and metrics after an incident, writing the post-mortem, and suggesting what to fix — but not writing the fix themselves.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; &lt;em&gt;“Conversion dropped 12% last week. I dug into the funnel data and found that 80% of drop-offs happen on the new checkout page on mobile devices. I recommend we prioritize a mobile UX review.”&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;data-scientists&quot;&gt;Data Scientists&lt;/h3&gt;
&lt;p&gt;Data scientists are closer to R&amp;#x26;D engineers. They don’t just analyze what happened — they build things that &lt;em&gt;predict&lt;/em&gt; what will happen or &lt;em&gt;automate&lt;/em&gt; decisions. Their output is algorithms, trained ML models, or heuristics that engineering integrates into production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In engineering terms:&lt;/strong&gt; if a data scientist were a developer, they’d be the one writing a proof-of-concept for a new feature — except their “feature” is a mathematical model that needs your infrastructure to run.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; &lt;em&gt;“We trained a recommendation model that predicts which products a user is likely to buy based on their browsing history. It improves click-through rate by 15% in our offline tests. We need engineering to integrate it into the product page — the model takes a user ID and returns a ranked list of product IDs in ~10ms.”&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-data-science-and-engineering-work-together&quot;&gt;How Data Science and Engineering Work Together&lt;/h2&gt;
&lt;p&gt;Data science and software engineering don’t work in isolation. There are three distinct phases where the two disciplines intersect — and each has different needs.&lt;/p&gt;
&lt;h3 id=&quot;phase-1-data-science-research&quot;&gt;Phase 1: Data Science Research&lt;/h3&gt;
&lt;p&gt;This is the exploratory phase. Think of it as the data scientist’s playground.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Needs ad-hoc query capabilities on big data&lt;/li&gt;
&lt;li&gt;Needs historical data — current data alone is mostly unusable for research; timelines matter&lt;/li&gt;
&lt;li&gt;Very individual — every data scientist works differently, with their own tools and workflows&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;phase-2-model-training&quot;&gt;Phase 2: Model Training&lt;/h3&gt;
&lt;p&gt;A more structured phase where models get trained and validated.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;More aligned tooling, possibly standardized across a team or company&lt;/li&gt;
&lt;li&gt;Needs query capabilities on big data&lt;/li&gt;
&lt;li&gt;Needs historical data (e.g. snapshots from various points in the past)&lt;/li&gt;
&lt;li&gt;A more stable, repeatable approach to querying data&lt;/li&gt;
&lt;li&gt;Data lineage becomes important: who uses what data, for what purpose, and what are the dependencies&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;phase-3-software-engineering-integration&quot;&gt;Phase 3: Software Engineering Integration&lt;/h3&gt;
&lt;p&gt;This is where engineering takes over — integrating the algorithm or ML model into the production system.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can be offline (batch) or online (real-time) — more on this below&lt;/li&gt;
&lt;li&gt;Requires tight alignment on data formats, types, and semantics&lt;/li&gt;
&lt;li&gt;Fast database queries: all data including feature data must be loaded in milliseconds&lt;/li&gt;
&lt;li&gt;No historical data needed — only current data matters in production&lt;/li&gt;
&lt;li&gt;Data access may be charged per query, so optimize for efficient database usage&lt;/li&gt;
&lt;li&gt;Smart caching for feature data may be needed to reduce latency and cost&lt;/li&gt;
&lt;li&gt;May need to log predictions for future model training (feedback loop)&lt;/li&gt;
&lt;li&gt;Operations monitoring, SLA/SLO — are ML predictions working as expected? Latency, error rates, prediction quality&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;keys-to-good-collaboration&quot;&gt;Keys to Good Collaboration&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Start early.&lt;/strong&gt; Data scientists and software engineers need to collaborate already in late research phase. Why? Because integrating some ML features as well as the type of model in production can be a deal-breaker. Often features that sound easy from a data science perspective are hard to implement in engineering — or vice versa. The engineering must also be able to load and use the model on their tech stack.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Get the data right.&lt;/strong&gt; When engineering integrates an ML model, it’s crucial that the data types and semantics match exactly what the data scientist used during training. If you use two different tech stacks, things get tricky — there can be semantic differences between online and offline data. Or there can simply be bugs. Even if the tech-stack is the same the data-sources may not. Ensure that the data-science database (eg DWH) aligns with the engineering database (online).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agree on the model format early.&lt;/strong&gt; Both sides need to be able to work with the chosen type of ML model. Data science needs to train it effectively, while engineering needs to load it and run predictions/inferences in production. From an engineering perspective, what matters is: how big is the model (memory, load time), and do we have libraries to load this model type in our stack? This becomes critical when the tech stacks differ — e.g. data science uses Python/Airflow while engineering runs .NET or Java backends. A model format that’s trivial to export in Python might have no mature loader in your production runtime. Solve this before anyone starts training.&lt;/p&gt;
&lt;h2 id=&quot;offline-vs-online-the-most-important-distinction&quot;&gt;Offline vs. Online: The Most Important Distinction&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2026/online_vs_offline.png&quot; alt=&quot;Offline vs. Online ML predictions&quot;&gt;&lt;/p&gt;
&lt;p&gt;This is where most of the engineering complexity lives.&lt;/p&gt;
&lt;h3 id=&quot;offline-batch-predictions&quot;&gt;Offline (Batch Predictions)&lt;/h3&gt;
&lt;p&gt;From an engineering perspective, offline means running ML predictions in batch jobs — typically on a schedule.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Latency doesn’t matter — jobs can take minutes or hours&lt;/li&gt;
&lt;li&gt;Data freshness doesn’t matter — you work with whatever snapshot is available&lt;/li&gt;
&lt;li&gt;Results are pre-calculated and stored for fast lookup by the online system&lt;/li&gt;
&lt;li&gt;Stability is secondary — a failed batch can be retried without user impact&lt;/li&gt;
&lt;li&gt;Resource costs (memory, storage, compute) still need attention&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;A practical example:&lt;/strong&gt; Calculate trending products every 2 hours. Once done, write the results to a fast key-value store where the online system picks them up.&lt;/p&gt;
&lt;h3 id=&quot;online-near-real-time&quot;&gt;Online (Near Real-Time)&lt;/h3&gt;
&lt;p&gt;Online means the user is waiting — your service needs to load the model, gather feature-data, run inference, and return a result within a single request.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Engineering challenges:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Total response time often needs to be below 50ms — including feature loading and inference&lt;/li&gt;
&lt;li&gt;The ML model must be loaded in memory and ready to serve (cold starts are a killer)&lt;/li&gt;
&lt;li&gt;The ML model updates most be loaded while staying full operational&lt;/li&gt;
&lt;li&gt;May support A/B testing of ML models — not one but two models must hot loaded in memory&lt;/li&gt;
&lt;li&gt;To detect model skew you need some kind of model validation (eg. run a well defined test-case the model is loaded into memory but before you use the model for serving user requests)&lt;/li&gt;
&lt;li&gt;Feature data must be queryable in milliseconds — this is often the actual bottleneck, not the inference itself&lt;/li&gt;
&lt;li&gt;Data must be kept current via streaming pipelines (e.g. Kafka, Pub/Sub) into a fast store&lt;/li&gt;
&lt;li&gt;Everything must be failsafe with graceful fallbacks — if the model fails, the user shouldn’t notice&lt;/li&gt;
&lt;li&gt;Must scale horizontally under load&lt;/li&gt;
&lt;li&gt;Cloud costs can spike quickly — every query, every byte of storage adds up&lt;/li&gt;
&lt;li&gt;Massive tracking data for model inferences need to be collected stored while under full load&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;When you can’t avoid online predictions:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When real-time data is needed as model input (e.g. products viewed in the current session)&lt;/li&gt;
&lt;li&gt;When the number of feature combinations is too large to pre-calculate — you can’t pre-compute every possibility&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What engineering typically needs to build:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A feature store with millisecond read latency, fed by streaming data.
For a large E-Commerce site like Digitec-Galaxus expect hundreds of GB if not TB’s of data. Collections/tables can contain multi-million documents/rows each.&lt;/li&gt;
&lt;li&gt;Model serving infrastructure (load &amp;#x26; validation, version, swap models without downtime)&lt;/li&gt;
&lt;li&gt;A distributed caching layer for frequently requested feature data (not for prediction results)&lt;/li&gt;
&lt;li&gt;Monitoring for prediction latency, error rates, and model quality (drift &amp;#x26; skew detection)&lt;/li&gt;
&lt;li&gt;Logging of predictions and inputs for future model retraining&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;decision-framework-offline-or-online&quot;&gt;Decision Framework: Offline or Online?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Default to offline if you can.&lt;/strong&gt; Challenge requirements so you don’t need real-time online ML predictions. Two factors push you toward online:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data freshness&lt;/strong&gt; — if you need very current data, you can’t pre-calculate every few hours. At some point, you have to do it in real-time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Granularity&lt;/strong&gt; — if the model has many features or a feature has a wide range of values, pre-calculating all combinations becomes infeasible. But if the model only needs a product ID and an age group, you can pre-calculate rows like &lt;code&gt;(product_id, age_group) → recommendation&lt;/code&gt; — even millions of rows are fine for today’s cloud databases.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;tips-for-online-ml&quot;&gt;Tips for Online ML&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Don’t use slow or costly models in online scenarios
&lt;ul&gt;
&lt;li&gt;Challenge to use an efficient model for the job; not the fanciest newest thing&lt;/li&gt;
&lt;li&gt;Quantise the model for production (data-scientist can do this after they trained the model but often you need to tell them to do so)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Custom ML models can be quantized — this reduces model size dramatically and makes inference fast&lt;/li&gt;
&lt;li&gt;Remember: the bottleneck is usually data loading, not inference&lt;/li&gt;
&lt;li&gt;Design your feature store for millisecond lookups with streaming updates&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;drift-vs-skew--know-the-difference&quot;&gt;Drift vs. Skew — Know the Difference&lt;/h3&gt;
&lt;p&gt;Two terms you’ll hear from data scientists that matter for engineering:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Model drift&lt;/strong&gt; means the model’s predictions get worse &lt;em&gt;over time&lt;/em&gt; because the real world changed. The patterns it learned during training no longer match reality. Example: a recommendation model trained on pre-pandemic shopping behaviour performs poorly after consumer habits shifted. Engineering’s job: monitor prediction quality and trigger retraining when metrics degrade.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Model skew&lt;/strong&gt; is a mismatch between training data and serving data — same point in time, but the data looks different due to technical inconsistencies. Example: during training the feature “user_age” was a float, but in production it arrives as an integer. Engineering’s job: ensure the feature pipeline produces identical data formats and semantics in both offline training and online serving.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt; &lt;em&gt;drift&lt;/em&gt; = the world changed, &lt;em&gt;skew&lt;/em&gt; = your pipeline has a bug.&lt;/p&gt;
&lt;h3 id=&quot;what-does-quantize-a-model-mean&quot;&gt;What Does “Quantize a Model” mean?&lt;/h3&gt;
&lt;p&gt;ML models store their learned knowledge as millions of numerical weights — typically as 32-bit floating point numbers. Quantization reduces the precision of these weights, for example from 32-bit floats to 8-bit integers. The model file gets dramatically smaller (often 4x), loads faster, and runs inference quicker — with only a small, often negligible loss in prediction accuracy.&lt;/p&gt;
&lt;p&gt;Why this matters for engineering: a quantized model uses less memory, starts faster (critical for scaling and cold starts), and is cheaper to serve. Data scientists can quantize after training, but they often don’t think about it unless you ask. Make it part of your handover checklist.&lt;/p&gt;
&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing Thoughts&lt;/h2&gt;
&lt;p&gt;Neither data science nor engineering can deliver ML value alone. Collaborate early, push back when something won’t work in production, and stay in regular contact — not just at handover points. A tricky feature for engineering might have a simpler alternative that data science can explore while still in research. The best ML systems are built by teams where both sides understand each other’s constraints.&lt;/p&gt;</content:encoded></item><item><title>Tech stack for hosting small apps on Azure for free</title><link>https://marcduerst.com/blog/tech-stack-for-hosting-small-apps-on-azure-for-free/</link><guid isPermaLink="true">https://marcduerst.com/blog/tech-stack-for-hosting-small-apps-on-azure-for-free/</guid><description>I’m sometimes doing web apps for hobby/personal projects which I like to host online just very low cost or for free. I have the following set-up in mind for ...</description><pubDate>Sun, 08 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m sometimes doing web apps for hobby/personal projects which I like to host online just very low cost or for free. I have the following set-up in mind for quite some time and finally took the time to explore it and got it run. In this post I write my findings.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;With Azure Functions and Azure Storage Accounts combined, you get a powerful and very cheap or free stack for smaller projects running SPA’s, .Net backends and storing various kinds of data.&lt;/p&gt;
&lt;p&gt;As always, it needs tome time to figure the nasty details on how to connect the building blocks. Also have a look at the limitations. You also must be open on new tech and not just require good old MS-SQL server.&lt;/p&gt;
&lt;h2 id=&quot;my-requirements&quot;&gt;My requirements&lt;/h2&gt;
&lt;p&gt;Basically my wish list from the technical side with focus on web-frontend and backend. In the future, maybe native mobile-apps will join.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Backend&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Modern .Net (Version 6/7/x)&lt;/li&gt;
&lt;li&gt;Supported facades: API’s (HTTP), scheduled Jobs (Timer), message handlers (Queues/Events)&lt;/li&gt;
&lt;li&gt;Support storages: no-SQL, blobs, queues, optional: SQL/relational, optional: others&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frontend&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Support for SPA frameworks (Rect/Next or others)&lt;/li&gt;
&lt;li&gt;Custom domains&lt;/li&gt;
&lt;li&gt;Free to use any CSS-frameworks, component-libraries etc.&lt;/li&gt;
&lt;li&gt;Frontend can call the backend API (HTTPS, CORS, TLS, …)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Mobile Apps
&lt;ul&gt;
&lt;li&gt;Possibility to communicate to the backend for native mobile apps in the future&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;choose-tech-stack&quot;&gt;Choose tech-stack&lt;/h2&gt;
&lt;p&gt;To host projects with the above stack with low or no costs, I came up with the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Repository:&lt;/strong&gt; GitHub
&lt;ul&gt;
&lt;li&gt;Free for personal, small or open-source projects&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CI / CD:&lt;/strong&gt; GitHub Actions
&lt;ul&gt;
&lt;li&gt;Some usage for free included in GitHub repo.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backend:&lt;/strong&gt; Azure Serverless Function app(s) written in .Net C# 7
&lt;ul&gt;
&lt;li&gt;Supports HTTP, timers, queues, storage and others as triggers&lt;/li&gt;
&lt;li&gt;In the &lt;a href=&quot;https://azure.microsoft.com/en-us/pricing/details/functions/?ef_id=_k_Cj0KCQjwpompBhDZARIsAFD_Fp-TTdIzo66crtFpslOp8O3FClFO38UYvgfLGILERIuMTe2yKypYxLsaAn88EALw_wcB_k_&amp;#x26;OCID=AIDcmmtg9dwtad_SEM__k_Cj0KCQjwpompBhDZARIsAFD_Fp-TTdIzo66crtFpslOp8O3FClFO38UYvgfLGILERIuMTe2yKypYxLsaAn88EALw_wcB_k_&amp;#x26;gclid=Cj0KCQjwpompBhDZARIsAFD_Fp-TTdIzo66crtFpslOp8O3FClFO38UYvgfLGILERIuMTe2yKypYxLsaAn88EALw_wcB#pricing&quot;&gt;consumption&lt;/a&gt; plan, there is a decent compute amount included for free: 400’000 GB-s.&lt;br&gt;
&lt;strong&gt;Tip:&lt;/strong&gt; Set a daily usage consumption on max. 13’000 GB-s/day to make sure you stay in free tier. Change this to our app and budget needs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data:&lt;/strong&gt; Azure Table Storage (part of Azure Storage Account), an option is Azure Cosmos DB with its &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/cosmos-db/free-tier&quot;&gt;free tier&lt;/a&gt; (&amp;#x3C;1000 RU/s, &amp;#x3C;25 GB)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blobs/Fles:&lt;/strong&gt; Azure Blob Storage (part of Azure Storage Account)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Messaging:&lt;/strong&gt; Azure Storage Queue (part of Azure Storage Account)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frontend:&lt;/strong&gt; Azure Blob Storage &lt;em&gt;Static Website&lt;/em&gt; (part of Azure Storage Account)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Telemetry/Monitoring:&lt;/strong&gt; Azure Application Insights (Azure Monitor &amp;#x26; Log-Analytics)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;azure-storage-accounts&quot;&gt;Azure Storage Accounts&lt;/h3&gt;
&lt;p&gt;All of my storage requirements for small projects are covered by Azure Storage Accounts. This service is &lt;a href=&quot;https://azure.microsoft.com/en-us/pricing/details/storage/blobs/&quot;&gt;very cheap&lt;/a&gt; (eg. €0.017 per GB/moth for Hot-Storage, €0.009 per GB/moth for Cold-Storage)! That’s basically free for most small projects.&lt;/p&gt;
&lt;p&gt;Azure Storage Accounts is the home for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Blob storage:&lt;/strong&gt; storing files/buckets/etc. in hierarchical containers. Optionally, you can also use file-sharing to upload and download files from Windows Explorer / Mac Finder – maybe interesting for some special use-cases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Table storage:&lt;/strong&gt; simple and highly scalable NoSQL data, with some restrictions on indexing and querying. Check the limitations and best-practice for partition- and row-keys before using it. Optionally supported by Azure Functions with input- and output-bindings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Queue:&lt;/strong&gt; Simple message-queues. Supported by Azure Functions as queue-/message-triggers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;azure-static-web-apps&quot;&gt;Azure Static Web Apps&lt;/h3&gt;
&lt;p&gt;Because the combination of Azure Functions and Azure Storage Accounts is very powerful to host backends and SPA’s, Microsoft is building a dedicated service around this called &lt;em&gt;Azure Static Web Apps&lt;/em&gt;. It simplifies the configurations and gives some advanced options but also introduce some limitations.&lt;/p&gt;
&lt;p&gt;A bonus is that you also get a Node-JS server where you can do things like server-side rendering.&lt;/p&gt;
&lt;h4 id=&quot;limitations&quot;&gt;Limitations&lt;/h4&gt;
&lt;p&gt;One limitation that hit me, was that the Azure Functions only supporting HTTP triggers; timers, queues and other triggers are not (yet?) supported.&lt;/p&gt;
&lt;p&gt;Another limitation: the free plan does not support “bring your own Functions backend” and therefore you can not work around the above limit by bringing our own Azure Functions instance.&lt;/p&gt;
&lt;p&gt;None of these limitations you have when using your own custom Azure Function instance.&lt;/p&gt;
&lt;h2 id=&quot;resulting-azure-resource-group&quot;&gt;Resulting Azure Resource Group&lt;/h2&gt;
&lt;p&gt;To give you an idea, here is what my Azure Resource Group looks like. My PoC is analyzing free parking spaces in the City of Zürich. Don’t look too close on my naming – it’s just a proof of concept 😉.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2023/10/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Some points of interest:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Custom Azure Functions App to get timer support&lt;/li&gt;
&lt;li&gt;Custom Azure Storage Account to host my tables and the static website (SPA). Separate from the Functions own internal Storage Account.&lt;/li&gt;
&lt;li&gt;Standard Application Insights instance&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;/h2&gt;
&lt;p&gt;I don’t like to go into every detail here, but some tips on things I struggled with.&lt;/p&gt;
&lt;h3 id=&quot;secure-access-to-data&quot;&gt;Secure access to data&lt;/h3&gt;
&lt;p&gt;To keep the data save, I restricted the access to my Azure Table Storage using an Azure Managed Identity. It needed the “Storage Table Data Contributor” role.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2023/10/image-4.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;static-web-app&quot;&gt;Static web app&lt;/h3&gt;
&lt;p&gt;In Azure Storage Account there is a menu-item called “Static Website”. Enable it to get the required “$web” blob container. Place your SPA files and assets in this container – it is your web-root. See below for my GitHub Actions workflow on how you deploy it into this container.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2023/10/image-3.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;cors-browser-security&quot;&gt;CORS (Browser Security)&lt;/h3&gt;
&lt;p&gt;It took me a while until I figured where to add the CORS headers. They are needed because with this setup, your backend and your web-hosting (SPA) use different domains (=origins).&lt;/p&gt;
&lt;p&gt;In the Azure Functions app, there is “CORS” menu-item. Add the domain / URL of your SPA app.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2023/10/image-2.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In the blob storage (static website) there are CORS headers too. You’ll find it under “Resource Sharing (CORS)”. Add the URL / domain of your Azure Functions backend in there.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2023/10/image-1.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;ci--cd-with-github-actions&quot;&gt;CI / CD with GitHub Actions&lt;/h3&gt;
&lt;p&gt;Deploying the Azure Functions app is mostly using the generated GitHub Actions YAML file with a few tweaks like the path filters in the trigger. I set them so only backend-changes or changes to the backends CI/CD, trigger a backend build&amp;#x26;deploy.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Backend - Build and deploy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    branches&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    paths&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;src/ParkingZuerichAnalytics/**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.github/workflows/backend_parkingzuerichanalytics.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  workflow_dispatch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  AZURE_FUNCTIONAPP_PACKAGE_PATH&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;./src/ParkingZuerichAnalytics/ParkingZuerichAnalytics.DataGathering&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  DOTNET_VERSION&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;7.0.x&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  build-and-deploy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    runs-on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    steps&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Checkout GitHub Action&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/checkout@v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Setup DotNet ${{ env.DOTNET_VERSION }} Environment&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/setup-dotnet@v1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          dotnet-version&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ env.DOTNET_VERSION }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Resolve Project Dependencies Using Dotnet&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        shell&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          pushd &apos;./${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          dotnet build --configuration Release --output ./output&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          popd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Run Azure Functions Action&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Azure/functions-action@v1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        id&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;fa&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          app-name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;ParkingZuerichAnalytics&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          slot-name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Production&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          package&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/output&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          publish-profile&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ secrets.AZUREAPPSERVICE_PUB.... }}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Deploying the NextJS SPA was a little more effort. Important is the fact that you don’t get a Node server for your frontend. So you have to use the static export of NextJS. Depending on the lifetime of your data you also need to ‘use client’ so the client (Browser) will fetch the data, not the NextJS build-process.&lt;/p&gt;
&lt;p&gt;For a tutorial on how to deploy the static website, see &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blobs-static-site-github-actions?tabs=userlevel&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;App - Build and deploy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    branches&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    paths&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;src/parkingzuerich-app/**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.github/workflows/app_parkingzuerichanalytics.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  workflow_dispatch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;defaults&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    working-directory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;./src/parkingzuerich-app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  build-and-deploy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    runs-on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    steps&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Checkout GitHub Action&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/checkout@v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Install NodeJS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/setup-node@v1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          node-version&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;18&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Install packages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;npm install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Build static site&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;npm run build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Login to Azure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;azure/login@v1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          creds&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ secrets.AZURE_CREDENTIALS }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Upload to blob storage&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;azure/CLI@v1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          inlineScript&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            az storage blob upload-batch --account-name parkingzuerichapp  --auth-mode key -d &apos;$web&apos; -s ./src/parkingzuerich-app/out&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Logout from Azure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          az logout&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;always()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;alternatives&quot;&gt;Alternatives&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Hosting Next JS SPA: &lt;a href=&quot;https://vercel.com/solutions/nextjs?utm_source=google&amp;#x26;utm_medium=cpc&amp;#x26;utm_campaign=18576682558&amp;#x26;utm_campaign_id=18576682558&amp;#x26;utm_term=nextjs%20hosting&amp;#x26;utm_content=141733726745_665293501632&amp;#x26;gad=1&amp;#x26;gclid=Cj0KCQjwpompBhDZARIsAFD_Fp8PDjVSu_5Mpx5Tfy-9iIC2xz0SxpJSIBKoFV-Q04LUZpZgTPwcpbkaAlVeEALw_wcB&quot;&gt;Vercel&lt;/a&gt; has a free plan. Interesting if you use Node for your backend.&lt;/li&gt;
&lt;li&gt;Google Cloud (GCP): very cheap options for messaging (Google &lt;a href=&quot;https://cloud.google.com/pubsub&quot;&gt;PubSub&lt;/a&gt;) and no-sql data (Google &lt;a href=&quot;https://firebase.google.com/docs/firestore&quot;&gt;Firestore&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;closing&quot;&gt;Closing&lt;/h2&gt;
&lt;p&gt;If you open your mind to new tech, you can get really cheap hosting for your smaller projects. Just stay under the radar to not trigger the expensive limits. Make a PoC if things work for you.&lt;/p&gt;
&lt;p&gt;Hope this helps and inspires!&lt;/p&gt;</content:encoded></item><item><title>Monitor a pod&apos;s container resources in GCP</title><link>https://marcduerst.com/blog/monitor-a-pods-container-resources-in-gcp/</link><guid isPermaLink="true">https://marcduerst.com/blog/monitor-a-pods-container-resources-in-gcp/</guid><description>Recently, we switched to GKE (Google Kubernetes Cluster) “autopilot” with the whole cluster. Autopilot is a feature where Google will manage the required VM’...</description><pubDate>Wed, 01 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently, we switched to GKE (Google Kubernetes Cluster) “autopilot” with the whole cluster. Autopilot is a feature where Google will manage the required VM’s / Scale-Sets for you. You will not need to specify, monitor, scale or even pay for VM’s and therefore IaaS. Instead, you specify what workloads (services and cronjobs) you have, and how much CPU and memory they need. These are called resource “request”. GKE needs this information to do proper horizontal auto-scaling. You finally pay with autopilot is the total-requested CPU and memory of all your Pods (Instances) – no matter how many VMs and what size of VM’s is needed to run all this.&lt;/p&gt;
&lt;h3 id=&quot;the-problem&quot;&gt;The problem&lt;/h3&gt;
&lt;p&gt;How to find the right values on how much CPU and memory each of your workload uses?&lt;/p&gt;
&lt;p&gt;If you go to the GCP console – the web-UI of the Google Cloud – you can drill down to your workload details and get something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2023/01/image.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;You see how many vCPU’s all your Pods need together. The red line is what one specified in the deployment YAML files. First though: nice and quick overview.&lt;/p&gt;
&lt;p&gt;But this can be miss-leading as it shows the aggregated statistics of all containers instances running in all your pod’s. Especially with autopilot, resource requirements are managed strictly per container.&lt;/p&gt;
&lt;p&gt;So the question is, how much CPU and memory does each of your container really use/need? What does one have to specify in the YAML for which container?&lt;/p&gt;
&lt;h3 id=&quot;the-solution&quot;&gt;The solution&lt;/h3&gt;
&lt;p&gt;You can monitor the resource-usage of your containers in the Google Metrics Explorer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CPU&lt;/strong&gt; is found in &lt;em&gt;Kubernetes Container&lt;/em&gt; &gt; &lt;em&gt;Container&lt;/em&gt; &gt; &lt;em&gt;CPU usage time&lt;/em&gt;. &lt;strong&gt;Memory&lt;/strong&gt; just next to it in &lt;em&gt;Kubernetes Container&lt;/em&gt; &gt; &lt;em&gt;Container&lt;/em&gt; &gt; &lt;em&gt;Memory usage&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2023/01/image-1.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Then a lot of lines will be shown in a diagram: one for each container (not pod) in your cluster:&lt;/p&gt;
&lt;p&gt;Not quite that helpful 😁.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Pro-tip:&lt;/strong&gt;&lt;/strong&gt; add a filter on “app” which is the name of your workload:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2023/01/image-3.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;When you get all running containers for the given workload like this and on the right side you see the number of cpu’s for the given container and point in time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2023/01/image-4.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I’d say this is better, but still not perfect. Our pods normally have two or three containers running per pod. For example, our own backend-service and an Istio (mesh) sidecar and sometimes even a Google Cloud SQL proxy. All of these containers are shown in the above diagram as well.&lt;/p&gt;
&lt;p&gt;As you have to specify the resource requests per container, you normally like to take a look at a single container type. For example, workload (=app) “CustomerBackend”, container (=&lt;em&gt;container_name&lt;/em&gt;) “istio-proxy”.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Pro-tip:&lt;/strong&gt;&lt;/strong&gt; add a filter on container-name.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2023/01/image-5.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now the chart looks better, and you see relatively good, what the &lt;em&gt;istio-proxy&lt;/em&gt; container of your &lt;em&gt;customer-backend&lt;/em&gt; workload really uses:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2023/01/image-6.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Compare the value on the Y axis with the request values you have in our yaml or Helm chart and adjust them if needed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pro-tip:&lt;/strong&gt; you can also use other features of the metrics explorer like group, e.g. by &lt;em&gt;container_name&lt;/em&gt;. To count the instances running over the time, you can filter by &lt;em&gt;app&lt;/em&gt; and group by &lt;em&gt;container_name&lt;/em&gt; and then aggregate the &lt;em&gt;count&lt;/em&gt;. You can even go further and build your custom GCP dashboard based on the metrics settings with filter variables, so you can use the dashboard to check each of your workloads by using the filter toolbar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A note on hitting the requested CPU and memory limits:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If the CPU values reach the value of your requested CPU, the container gets suspended for a while by the underlying Linux kernel. Normally this is not helpful and gives you other issues. Especially containers like the &lt;em&gt;istio-proxy&lt;/em&gt; (e.g. used by Google Anthos) don’t like to be suspended as they control all the network traffic in and out of your pods. They also control network access for Google services like the GKE meta-data store. This is needed to inject your workload settings (environment variables) into your application containers.&lt;/p&gt;
&lt;p&gt;Hitting the memory limit is about what you may expect: classic out of memory errors will occur.&lt;/p&gt;
&lt;p&gt;I guess you can imagine all sorts of strange errors coming out of these situations. So don’t just set the values for your application container right, but also for the supporting containers your pod runs.&lt;/p&gt;
&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
&lt;p&gt;It’s hard to get the request values for CPU and memory right, as the container have peaks and lows. But it’s important to keep them running smoothly and on the other hand don’t pay too much for your cloud compute power.&lt;/p&gt;
&lt;p&gt;The Google Metrics Explorer is your fried here and offers many metrics and features to nail down your cluster.&lt;/p&gt;
&lt;p&gt;If you have Google Anthos (Istio) meshing configured in your cluster, you get even more metrics out of it. You can even go one step further and use &lt;a href=&quot;https://keda.sh/&quot;&gt;KEDA&lt;/a&gt; to do event-based auto-scaling of your pods using many more metrics. This all works great with GKE autopilot on our clusters.&lt;/p&gt;</content:encoded></item><item><title>Scale and fix a Azure Service Fabric cluster</title><link>https://marcduerst.com/blog/scale-and-fix-a-azure-service-fabric-cluster/</link><guid isPermaLink="true">https://marcduerst.com/blog/scale-and-fix-a-azure-service-fabric-cluster/</guid><description>After having not quite an easy time fixing our production server-cluster manually I like to write a few things down so maybe other or my future self will fin...</description><pubDate>Thu, 01 Apr 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;After having not quite an easy time fixing our production server-cluster manually I like to write a few things down so maybe other or my future self will find these information useful.&lt;/p&gt;
&lt;h3 id=&quot;situation&quot;&gt;Situation&lt;/h3&gt;
&lt;p&gt;Our production server is a 5 node “Silver” cluster. It currently serves 17 services, 85 replicas. It serves 5 mio HTTP-Requests and about 25k users per day. This means that this system is fairly busy all day as we have users online also during night-times.&lt;/p&gt;
&lt;p&gt;This system reported failed Service Fabric Cluster Upgrades because one node did not update (timeout) for some reason. Service Fabric Cluster Upgrades are initiated by Microsoft to update the cluster-runtimes on the machines.&lt;/p&gt;
&lt;p&gt;Because we can not RDP into these nodes for security reason (working on this right now) we decided – together with Microsoft Support – to simply replace the “broken” node with a fresh one. That’s where our Service-Fabric manual scaling adventure started.&lt;/p&gt;
&lt;h3 id=&quot;learning-get-a-healthy-cluster-after-each-operation&quot;&gt;Learning: Get a healthy cluster after each operation&lt;/h3&gt;
&lt;p&gt;After you have done an operation on your cluster get a healthy cluster before starting the next operation. Otherwise your cluster can get into serious trouble if problems are start summarise up.&lt;/p&gt;
&lt;h3 id=&quot;learning-how-to-scale-out-in-manually&quot;&gt;Learning: How to scale-out/-in manually&lt;/h3&gt;
&lt;p&gt;Every Service-Fabric has its associated Azure VM-Scalue-Set underneath. The scale-set consists of a set of identical VM’s. These VM’s have the Service-Fabric extension installed and that is how Service Fabric Cluster Manager connects and controls the VM’s. Each VM becomes a “node” in the cluster. Its also recommended to have multiple scale-sets per fabric. At least one for the so called “seed” nodes and another for the application-services. We don’t do that (yet) because of simplicity and budget.&lt;/p&gt;
&lt;p&gt;If you like to have additional nodes on your Service-Fabric you simply can change the number the number of VM’s in your scale-set and wait some time. It may take of up to an hour before the VM’s are provisioned and become full nodes with our software running on it. If you don’t need the additional power (nodes) anymore you simply can scale the VM scale-set accordingly. You find these scaling option in the Azure Portal on our VM scale-set under “Scaling”.&lt;/p&gt;
&lt;p&gt;Here is a more detailed &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-cluster-scaling&quot;&gt;documentation&lt;/a&gt; from Microsoft.&lt;/p&gt;
&lt;h3 id=&quot;learning-never-ever-go-below-3-nodes&quot;&gt;Learning: Never ever go below 3 nodes&lt;/h3&gt;
&lt;p&gt;No matter what the reliability tier is (Bronze, Silver, Gold, Platinum), if you go below 3 nodes your Service-Fabric can completely break and is not accessible at all. We faced this issue several times on our dev/test environments. Lucky us we have scripted our infrastructure so we deleted the scale-set and service-fabric and re-depolyed them from scratch. Otherwise not even the Service Fabric Explorer (SFX) of those fabric’s was accessible anymore.&lt;/p&gt;
&lt;h3 id=&quot;learning-seed-nodes-promotion&quot;&gt;Learning: Seed nodes promotion&lt;/h3&gt;
&lt;p&gt;Seed nodes are nodes which some Service Fabric System stuff on it. Depending on our reliability tier Service-Fabric needs 1 (None), 3 (Bronze), 5 (Silver), 7 (Gold) or 9 (Platinum) seed nodes. If a seed-node is un-healthy over about 2 hours or so the Service-Fabric will promote another node to a seed node automatically. So, if you run into this situation you just have to wait a decent time.&lt;/p&gt;
&lt;p&gt;Let’s say you did it the hard way and deleted a VM which was a seed-node. Service Fabric will list this node as seed-node with status “down”. You can not delete this node yet as it is a seed node. If you did not already have spin up a fresh VM with scale-out on the scale-set. Then wait up to two hours or so. SF will promote the healthy non-seed node to a seed-node. If this happens you can “Disable (remote data)” (see below how to get this option) and it will be removed from the node list.&lt;/p&gt;
&lt;h3 id=&quot;learning-node-management-in-sfx-with-advanced-mode&quot;&gt;Learning: Node management in SFX with “Advanced Mode”&lt;/h3&gt;
&lt;p&gt;The Azure Portal UI of Service-Fabric is fairly basic. If you like to have more insights or get a UI for advanced operations you need to use the Service Fabric Explorer (SFX). You’ll find a link to it in the Azure Portal of your Service-Fabric.&lt;/p&gt;
&lt;p&gt;On the nodes you get a “…” menu which – by default – has only a few options in it. And here is the trick we where told by Microsoft Support: Click on the gear-icon (“Settings”) on the top-right of the screen and activate the “Advanced mode” checkbox.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2021/04/advanced-mode.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now your “…” menu shows a bunch more options especially for the nodes. For example you then can “Disable (remove data)” and other disable options. This instructs SF to disable a node with the given ‘intent’. For example the “remove data” will shut down your services and remove the replicas. Wait a second to check that the node will not run your app/services anymore.&lt;/p&gt;
&lt;p&gt;These options are helpful if you like to remove nodes for some reason. If you do this using Power-Shell or Azure CLI you can use the &lt;em&gt;–force&lt;/em&gt; option so you don’t have to wait on seed-node timeouts. But again: never ever go below 3 healthy seed-nodes. If you need to remove one, first make sure you spin up new nodes before so after the removal you still have at least 3 healthy seed-nodes.&lt;/p&gt;
&lt;h3 id=&quot;learning-sf-will-not-re-balance-fault-domain-if-you-scale-manually&quot;&gt;Learning: SF will not re-balance fault-domain if you scale manually&lt;/h3&gt;
&lt;p&gt;When you do things like to above operations it can happen, that you cluster-map ist “not balanced” anymore. This means that some of the nodes share upgrade- or fault-domains. You see this in the tab “Cluster Map” of the SFX.&lt;/p&gt;
&lt;p&gt;A balanced cluster-map looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2021/04/sfx-cluster-map.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Service-Fabric will not fix this if you scaled manually or if you manually removed nodes. You have to take care of it.&lt;/p&gt;
&lt;p&gt;A fault-domain can not be changed easily because it defines where you VM physically lives. To change this you need to get a new VM in place eg. by scale-out again. If you have VM’s in the right spot of your cluster-map you can remove the obsolete VM’s. To do so, first disable them in SFX with the remove-data option. When the replicas are down, you can delete the VM’s in the VM scale-set using Azure Portal or CLI.&lt;/p&gt;
&lt;h2 id=&quot;learning-use-supported-vm-sizes&quot;&gt;Learning: Use supported VM-sizes&lt;/h2&gt;
&lt;p&gt;When you do a scale-up or scale-down by selecting a new VM-size make sure you choose one that is supported by Service-Fabric otherwise your Service-Fabric can explore so you can not access it anymore and have to start over from scratch (re-create SF and Scale-Set).&lt;/p&gt;
&lt;p&gt;The bad thing: there is no safety belt when re-sizing VM’s. You will not get any warning or so but your SF will break afterwards.&lt;/p&gt;
&lt;p&gt;Check the Microsoft Documentation &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-vertical-scale-reprovision&quot;&gt;here…&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;There are several things one needs to know (or learn) for operating a production Service Fabric Cluster. If you don’t you can burn down your cluster if you do the wrong thing.&lt;/p&gt;
&lt;p&gt;Therefore make sure you have a multi-node test-cluster with 3 nodes or so. Its still not the same as a production cluster with 5 or more nodes (see the fault-domain limitations) but at least you can try most of the things on the test-cluster first.&lt;/p&gt;</content:encoded></item><item><title>Order Azure Log Analytics result columns</title><link>https://marcduerst.com/blog/order-azure-log-analytics-result-columns/</link><guid isPermaLink="true">https://marcduerst.com/blog/order-azure-log-analytics-result-columns/</guid><description>When doing a Kusto query in Azure Log Analytics the result set (Grid) gets rebuild every single time a query is executed. The default order of the columns is...</description><pubDate>Tue, 01 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;problem&quot;&gt;Problem&lt;/h2&gt;
&lt;p&gt;When doing a Kusto query in Azure Log Analytics the result set (Grid) gets rebuild every single time a query is executed. The default order of the columns is somewhat random. This normally means that I have to reorder the important columns like level, message etc. manually by dragging them to the first position. If they are not even shown I first need to show them using the column picker drop-down.&lt;/p&gt;
&lt;p&gt;This is no fun and I finally found the trick to build my “perfect” query so in don’t have to fiddle with the grid every time.&lt;/p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;/h2&gt;
&lt;p&gt;One of my favorite query is to query all our logs (&lt;em&gt;union *&lt;/em&gt;) for a given Correlation-ID (&lt;em&gt;where&lt;/em&gt;) over the past days (&lt;em&gt;ago(…)&lt;/em&gt;) and show the most important props as the first columns and then include all other columns / log values (&lt;em&gt;project-reorder&lt;/em&gt;) so I can expand a log row and still get all the log properties for this log entry. I order the list using the &lt;em&gt;Timestamp&lt;/em&gt; value as this one is more precise then &lt;em&gt;TimeGenerated&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Here is my query:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;union *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;| where LogProperties_CorrelationId_g == &quot;4869ea08-a9cf-49ed-a281-b5217655b65f&quot;  and Timestamp_t &gt; ago(7d)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;| order by Timestamp_t desc nulls last &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;| project-reorder TimeGenerated, Type, LogLevel_s, LogMessage_s, LogException_Message_s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hope this helps others.&lt;/p&gt;
&lt;p&gt;Let me know your cool and handy Kusto tricks!&lt;/p&gt;</content:encoded></item><item><title>Track SQL data with Azure alerts and dashboard charts</title><link>https://marcduerst.com/blog/track-sql-data-with-azure-alerts-and-dashboard-charts/</link><guid isPermaLink="true">https://marcduerst.com/blog/track-sql-data-with-azure-alerts-and-dashboard-charts/</guid><description>I’m trying already for quite some time to track the result of some SQL query in my Azure Dashboard and even better: trigger Azure Alerts when some condition ...</description><pubDate>Sun, 21 Jun 2020 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: screenshot-2020-06-21-at-17.10.42-1.png --&gt;
&lt;!-- MISSING IMAGE: screenshot-2020-06-21-at-17.15.59-1.png --&gt;
&lt;!-- MISSING IMAGE: screenshot-2020-06-21-at-17.16.51.png --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 3 images that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’m trying already for quite some time to track the result of some SQL query in my Azure Dashboard and even better: trigger Azure Alerts when some condition is reached. See my previous blog posts on Query &lt;a href=&quot;https://marcduerst.com/blog/query-sql-database-using-a-azure-logicapp&quot;&gt;SQL database using a Azure LogicApp&lt;/a&gt; and &lt;a href=&quot;https://marcduerst.com/blog/show-results-of-sql-query-on-azure-dashboard&quot;&gt;Show results of SQL query on Azure Dashboard&lt;/a&gt;. Thanks to to some ideas from my college we found a better approach to this requirements.&lt;/p&gt;
&lt;h2 id=&quot;goal&quot;&gt;Goal&lt;/h2&gt;
&lt;p&gt;We have a SQL query which returns us a count. We like to monitor this count in a Azure Dashboard chart and trigger Azure Alerts when they reach a certain value.&lt;/p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;/h2&gt;
&lt;p&gt;Here is the short version how we finally got in working:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a Azure Logic App with a “Schedule” trigger.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add action after the trigger to query the database (see &lt;a href=&quot;https://marcduerst.com/blog/query-sql-database-using-a-azure-logicapp&quot;&gt;here&lt;/a&gt;).&lt;br&gt;
&lt;strong&gt;Tip:&lt;/strong&gt; To know the structure of the SQL query result for the the next steps, run the Logic App and check the SQL query’s output.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use “Settings” on the query action and add a “Tracked Property” which logs the value from the query result to the diagnostic log.&lt;br&gt;
Expression in Tracked Properties value I used:&lt;br&gt;
&lt;code&gt;&quot;@int(body(&apos;Query_Event_Count&apos;)?[&apos;resultsets&apos;][&apos;Table1&apos;][0][&apos;count&apos;])&quot;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a diagnostic setting to log “WorkflowProcess” and “Send to Log Analytics”.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the Logic App and check everything is working.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wait about 5 minutes and check Log Analytics “Azure Diagnostics” for the query action and see if the “Tracked Property” got recorded correctly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a Log Analytics query which query the these tracked values.&lt;br&gt;
&lt;code&gt;AzureDiagnostics   | where TimeGenerated &amp;#x26;gt; ago(24h) and trackedProperties_countEvents_s != &quot;&quot;   | order by TimeGenerated desc nulls first   | project CountEvents=trackedProperties_countEvents_s&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use this query to define an Azure Alert Rule with source set to Log Analytics.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use the same query in a Azure Monitor “Workbook” to query and render a chart or whatever you like to visualize.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pin this workbook or only its chart to the Azure Dashboard.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title>Query SQL database using a Azure Logicapp</title><link>https://marcduerst.com/blog/query-sql-database-using-a-azure-logicapp/</link><guid isPermaLink="true">https://marcduerst.com/blog/query-sql-database-using-a-azure-logicapp/</guid><description>My goal was to define a LogicApp what can be called via HTTP request, query a SQL database with a select count query and return the result as text on the HTT...</description><pubDate>Sun, 05 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My goal was to define a LogicApp what can be called via HTTP request, query a SQL database with a &lt;code&gt;select count&lt;/code&gt; query and return the result as text on the HTTP response body. This is how my workflow looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2020/04/la_0_overview.png&quot; alt=&quot;la_0_overview&quot;&gt;&lt;/p&gt;
&lt;p&gt;First of all define a HTTP trigger:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2020/04/la_1_httptrigger.png&quot; alt=&quot;la_1_httptrigger&quot;&gt;&lt;/p&gt;
&lt;p&gt;The URL is generated after you save the step for the first time. By default HTTP triggers listen on HTTP POST verbs. You can change this to GET by adding a parameter on the trigger step.&lt;/p&gt;
&lt;p&gt;Next we need to execute a SQL query like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2020/04/la_2_sqlquery-1.png&quot; alt=&quot;la_2_sqlquery&quot;&gt;&lt;/p&gt;
&lt;p&gt;Next we need to extract the value from the query result. This is a little complicate because the result of the SQL query step is dynamic and therefore the designer can not assist us.&lt;/p&gt;
&lt;p&gt;Here is the expression I used:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;body(&apos;Query_Event_Count&apos;)?[&apos;resultsets&apos;][&apos;Table1&apos;][0][&apos;&apos;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Query_Event_Count&lt;/code&gt; is the name of the query step above.&lt;/li&gt;
&lt;li&gt;The last part &lt;code&gt;&apos;&apos;&lt;/code&gt; is the field name to extract. My &lt;code&gt;select count()&lt;/code&gt; return a empty field.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally we need to set a HTTP response which is straight forward. Note that I just return plain text as the body. You can get fancy here.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2020/04/la_5_httpresponse.png&quot; alt=&quot;la_5_httpresponse&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note on costs:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A Azure LogicApp costs per execution. Not much but it costs. If you plan to do a lot of HTTP calls this PoC is probably not what you are looking for.&lt;/p&gt;
&lt;p&gt;Here is the complete source-code of my LogicApp:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;definition&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &quot;$schema&quot;: &quot;https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &quot;actions&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &quot;Initialize_variable_2&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;inputs&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;variables&quot;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            &quot;name&quot;: &quot;countEvents&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            &quot;type&quot;: &quot;integer&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            &quot;value&quot;: &quot;@body(&apos;Query_Event_Count&apos;)?[&apos;resultsets&apos;][&apos;Table1&apos;][0][&apos;&apos;]\n&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;runAfter&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;Query_Event_Count&quot;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        &quot;Succeeded&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;type&quot;: &quot;InitializeVariable&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &quot;Query_Event_Count&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;inputs&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;body&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        &quot;query&quot;: &quot;select count(Id) from Events&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;host&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        &quot;connection&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            &quot;name&quot;: &quot;@parameters(&apos;$connections&apos;)[&apos;sql&apos;][&apos;connectionId&apos;]&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;method&quot;: &quot;post&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;path&quot;: &quot;/v2/datasets/@{encodeURIComponent(encodeURIComponent(&apos;default&apos;))},@{encodeURIComponent(encodeURIComponent(&apos;default&apos;))}/query/sql&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;runAfter&quot;: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;runtimeConfiguration&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;staticResult&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        &quot;name&quot;: &quot;Query_Event_Count0&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        &quot;staticResultOptions&quot;: &quot;Disabled&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;type&quot;: &quot;ApiConnection&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &quot;Response&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;inputs&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;body&quot;: &quot;@{variables(&apos;countEvents&apos;)} Events&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;statusCode&quot;: 200&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;kind&quot;: &quot;Http&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;runAfter&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;Initialize_variable_2&quot;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        &quot;Succeeded&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;type&quot;: &quot;Response&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &quot;contentVersion&quot;: &quot;1.0.0.0&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &quot;outputs&quot;: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &quot;parameters&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &quot;$connections&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;defaultValue&quot;: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;type&quot;: &quot;Object&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &quot;staticResults&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &quot;Query_Event_Count0&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;outputs&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;headers&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        &quot;ResultSets&quot;: &quot;Table1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;statusCode&quot;: &quot;OK&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;status&quot;: &quot;Succeeded&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &quot;triggers&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &quot;manual&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;inputs&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;method&quot;: &quot;GET&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;schema&quot;: {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;kind&quot;: &quot;Http&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;type&quot;: &quot;Request&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;parameters&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &quot;$connections&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &quot;value&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;sql&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;connectionId&quot;: &quot;/subscriptions/7be8.....&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;connectionName&quot;: &quot;sql-2&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    &quot;id&quot;: &quot;.....&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hope this helps others!&lt;/p&gt;</content:encoded></item><item><title>Show results of SQL query on Azure dashboard</title><link>https://marcduerst.com/blog/show-results-of-sql-query-on-azure-dashboard/</link><guid isPermaLink="true">https://marcduerst.com/blog/show-results-of-sql-query-on-azure-dashboard/</guid><description>I like to show the result of SQL Query on a Azure Dashboard. “Should be checken food” I thought. I checked a ton of options and finally got solution working.</description><pubDate>Sun, 05 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: dashboard_external_markdown_widget.png --&gt;
&lt;!-- MISSING IMAGE: dashboard_external_markdown.png --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 2 images that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I like to show the result of SQL Query on a Azure Dashboard. “Should be checken food” I thought. I checked a ton of options and finally got solution working.&lt;/p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;/h2&gt;
&lt;p&gt;One way I found was by writing a custom HTTP endpoint which returns Markdown text. I then added the Markdown widget and entered the endpoints URL as the external Markdown source.&lt;/p&gt;
&lt;p&gt;This is how it looks like when my endpoint returned the string “58 Events”:&lt;/p&gt;
&lt;p&gt;If you already have a AppService app or something similar you maybe like to integrate such “monitoring endpoints” in your solution. I didn’t like to to do it.&lt;/p&gt;
&lt;p&gt;So how did implement the custom HTTP endpoint? Because I had issues with Azure Functions and query a SQL database in the past I’ve chosen Azure LogicApp to do it.&lt;/p&gt;
&lt;p&gt;A LogicApp can be triggered on HTTP requests, can do SQL queries and can respond to HTTP requests. The down-side: LogicApps cost per execution. Not much but they cost. So its more proof-of-concept type of a solution. &lt;a href=&quot;https://marcduerst.com/blog/query-sql-database-using-a-azure-logicapp&quot;&gt;Read about my logic-app here…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Possible improvements:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use Azure Functions instead of the LogicApp.&lt;/li&gt;
&lt;li&gt;Use a web app instead of the LogicApp.&lt;/li&gt;
&lt;li&gt;Log it as log-events and use Azure Monitor Workbook to query it and build a nice report (workbooks can be pinned to Azure Dashboard).&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Azure DevOps: Retrieve Application Insights instrumentation key</title><link>https://marcduerst.com/blog/azure-devops-retrieve-application-insights-instrumentation-key/</link><guid isPermaLink="true">https://marcduerst.com/blog/azure-devops-retrieve-application-insights-instrumentation-key/</guid><description>How to retrieve the Application Insights instrumentation key in an Azure DevOps pipeline using PowerShell when the documented cmdlet doesn&apos;t work.</description><pubDate>Sat, 18 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I had to set up Azure Application Insights instances via an Azure DevOps CI/CD pipeline using ARM templates. It was straightforward — except for retrieving the newly created instrumentation key.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;
&lt;p&gt;I needed the instrumentation key of the newly created AppInsights instance to store it in the application’s Azure Key Vault, where the application reads its secrets from.&lt;/p&gt;
&lt;p&gt;I added an “Azure PowerShell” step to my pipeline to run a script with the right Azure context (subscription and resource group).&lt;/p&gt;
&lt;p&gt;According to &lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/module/azurerm.applicationinsights/get-azurermapplicationinsights?view=azurermps-6.13.0&quot;&gt;Microsoft’s documentation&lt;/a&gt;, there’s a PowerShell cmdlet called &lt;code&gt;Get-AzureRmApplicationInsights&lt;/code&gt; that should do the job. However, this cmdlet returned no value — and no error either.&lt;/p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;The Solution&lt;/h2&gt;
&lt;p&gt;I used three pipeline variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rg_name&lt;/code&gt; — the Azure Resource Group name&lt;/li&gt;
&lt;li&gt;&lt;code&gt;appinsights_name&lt;/code&gt; — the resource name of the AppInsights instance&lt;/li&gt;
&lt;li&gt;&lt;code&gt;appInsights_instrumentationkey&lt;/code&gt; — receives the instrumentation key&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following Azure PowerShell script did the trick:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Write-Host &quot;Resource Group Name: $(rg_name)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Write-Host &quot;AppInsights Name: $(appinsights_name)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$instrumentationKey = (Get-AzApplicationInsights -ResourceGroupName &quot;$(rg_name)&quot; -Name &quot;$(appinsights_name)&quot;).InstrumentationKey&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Write-Host &quot;Instrumentation Key: $instrumentationKey&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Write-Host &quot;##vso[task.setvariable variable=appInsights_instrumentationkey;]$instrumentationKey&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;whats-different&quot;&gt;What’s Different&lt;/h3&gt;
&lt;p&gt;The key insight: use &lt;code&gt;Get-AzApplicationInsights&lt;/code&gt; (the newer Az module) instead of &lt;code&gt;Get-AzureRmApplicationInsights&lt;/code&gt; (the deprecated AzureRM module). Call it to get all properties, then access &lt;code&gt;.InstrumentationKey&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The last line writes the value back to the pipeline variable &lt;code&gt;appInsights_instrumentationkey&lt;/code&gt; using the &lt;code&gt;##vso&lt;/code&gt; logging command.&lt;/p&gt;
&lt;h3 id=&quot;putting-it-together&quot;&gt;Putting It Together&lt;/h3&gt;
&lt;p&gt;A later step in the pipeline writes &lt;code&gt;appInsights_instrumentationkey&lt;/code&gt; to a Key Vault, where the application picks it up at runtime.&lt;/p&gt;
&lt;p&gt;Hope this helps!&lt;/p&gt;</content:encoded></item><item><title>Inject Xamarin Forms view models via IoC container</title><link>https://marcduerst.com/blog/inject-xamarin-forms-view-models-via-ioc-container/</link><guid isPermaLink="true">https://marcduerst.com/blog/inject-xamarin-forms-view-models-via-ioc-container/</guid><description>I started a new little project in my spare time which is a native mobile app for iOS and Android. Because the goal is to have as much shared code between iOS...</description><pubDate>Sat, 18 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I started a new little project in my spare time which is a native mobile app for iOS and Android. Because the goal is to have as much shared code between iOS and Android as possible and still have native apps experience I choose the Xamarin Forms stack. Its also an excellent opportunity to refresh my XAML know-how.&lt;/p&gt;
&lt;h1 id=&quot;the-problem&quot;&gt;The problem&lt;/h1&gt;
&lt;p&gt;I quickly got a screen working but missed a full fledged IOC container with proper constructor injection. There are libraries and article but most of them are outdated or even discontinued.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.microsoft.com/en-us/xamarin/xamarin-forms/enterprise-application-patterns/dependency-injection#resolution&quot;&gt;Dependency Injection&lt;/a&gt; documentation got me half way started. It contains mostly general information about dependency injection, inversion of control and so on. But it also has a sample implementation in &lt;a href=&quot;https://github.com/dotnet-architecture/eShopOnContainers&quot;&gt;this&lt;/a&gt; GitHub repo which was very helpful.&lt;/p&gt;
&lt;p&gt;For Xamarin Forms the recommended pattern for non-trivial apps is the MVVM pattern. Means we do a view using XAML (or C#) and connect it with a view-model using data-binding. The view-model contains all the UI logic and connect to other service classes – for example to retrieve data from a server.&lt;/p&gt;
&lt;p&gt;What I like to do is having view-models instantiated automatically using a IOC container so all the constructor injection takes place. As the view-models are the central part of MVVM apps we get IoC for wast majority of the app just with this alone.&lt;/p&gt;
&lt;p&gt;How to integrate an IOC container so the views get the view models injected and all dependencies are resolved as part of the constructor injection?&lt;/p&gt;
&lt;h1 id=&quot;solution&quot;&gt;Solution&lt;/h1&gt;
&lt;p&gt;As I like &lt;a href=&quot;https://simpleinjector.org&quot;&gt;SimpleInjector&lt;/a&gt; I choose this one but you can do basically the same with every other container that runs on .net Core and the Xamarin stack.&lt;/p&gt;
&lt;p&gt;The basic concept as described in Microsoft’s documentation goes like this (took me a while to get this):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;code&gt;ViewModelLocator&lt;/code&gt; which creates an &lt;em&gt;attached property&lt;/em&gt; for the views called &lt;code&gt;AutoWireViewModel&lt;/code&gt; (boolean).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When the &lt;code&gt;AutoWireViewModel&lt;/code&gt; is set the &lt;code&gt;ViewModelLocator&lt;/code&gt; looks for a matching view model class using a naming convention.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The view model gets resolved using SimpleInjector IoC container.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The view model instance then gets set as the views &lt;code&gt;BindingContext&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The normal binding kicks in because &lt;code&gt;BindingContext&lt;/code&gt; was set.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-view-model-locator&quot;&gt;The View Model Locator&lt;/h2&gt;
&lt;p&gt;Here is my ViewModelLocator similar to the one from the Microsoft documentation. You see that the &lt;code&gt;ViewModelLocator&lt;/code&gt; is a static class and hold a singleton reference to the SimpleInjector container. It also defines the &lt;code&gt;AutoWireViewModel&lt;/code&gt; property. In the change handler &lt;code&gt;OnAutoWireViewModelChanged&lt;/code&gt; you find the resolving of the view model and its assignment to &lt;code&gt;BindingContext&lt;/code&gt; of the view. Change this logic to your needs.&lt;/p&gt;
&lt;p&gt;In the static constructor I instantiate the SimpleInjector container called &lt;code&gt;Container&lt;/code&gt;. I then call my helper &lt;code&gt;IoCRegistrations.RegisterDependencies&lt;/code&gt; to do all the registrations.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ViewModelLocator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Container&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Container&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        static&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ViewModelLocator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            Container &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Container&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            IoCRegistrations.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RegisterDependencies&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Container);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; BindableProperty&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AutoWireViewModelProperty&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            BindableProperty.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CreateAttached&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                &quot;AutoWireViewModel&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                typeof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                typeof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ViewModelLocator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                default&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;                propertyChanged&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: OnAutoWireViewModelChanged);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; bool&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; GetAutoWireViewModel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;BindableObject&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; bindable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)bindable.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GetValue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(AutoWireViewModelProperty);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SetAutoWireViewModel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;BindableObject&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; bindable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; bindable.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SetValue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(AutoWireViewModelProperty, value);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RegisterSingleton&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TInterface&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; TInterface&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; where&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TInterface&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RegisterSingleton&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TInterface&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; T&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Resolve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GetInstance&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OnAutoWireViewModelChanged&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;BindableObject&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; bindable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; oldValue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; newValue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; view&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; bindable &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Element&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; viewType&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; view&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GetType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (viewType&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.FullName &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; viewName&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; viewType.FullName.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Replace&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;.Views.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;.ViewModels.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; viewAssemblyName&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; viewType.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GetTypeInfo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().Assembly.FullName;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; viewModelName&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CultureInfo.InvariantCulture, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;{0}ViewModel, {1}&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, viewName, viewAssemblyName);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; viewModelType&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Type.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GetType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(viewModelName);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (viewModelType &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; viewModel&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GetInstance&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(viewModelType);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            view.BindingContext &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; viewModel;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was the most tricky part.&lt;/p&gt;
&lt;p&gt;Just for the record here the helper for the IoC registrations:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IoCRegistrations&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RegisterDependencies&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Container&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; container&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RegisterSingleton&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IDataStore&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Item&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MockDataStore&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RegisterSingleton&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ICountryDataStore&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CountryDataStoreMock&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do whatever you need to do to get your stuff registered with the &lt;code&gt;container&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;usage-of-the-view-model-locator-in-the-view&quot;&gt;Usage of the View Model Locator in the View&lt;/h2&gt;
&lt;p&gt;All that is needed now is that the view sets the &lt;code&gt;AutoWireViewModel&lt;/code&gt; to true. Check out the line &lt;code&gt;base:ViewModelLocator.AutoWireViewModel=&quot;true&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;xml&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; version&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;1.0&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; encoding&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;utf-8&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ContentPage&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    xmlns&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;http://xamarin.com/schemas/2014/forms&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    xmlns&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;http://schemas.microsoft.com/winfx/2009/xaml&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    xmlns&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;views&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;clr-namespace:DiveSpots.Views&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    xmlns&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;clr-namespace:DiveSpots.ViewModels.Base;assembly=DiveSpots&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    base&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ViewModelLocator.AutoWireViewModel&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    x&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Class&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;DiveSpots.Views.WatersOverviewPage&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Visual&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Material&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Title&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;{Binding Title}&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;StackLayout&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;naming-convention&quot;&gt;Naming convention&lt;/h2&gt;
&lt;p&gt;I use the naming convention that the views are in the namespace &lt;code&gt;DiveSpots.Core.Views&lt;/code&gt; and their name ends with ‘View’ while the view models are in &lt;code&gt;DiveSpots.Core.ViewModels&lt;/code&gt; and there name is equal to the view but end with ‘ViewModel’. This can be changed or enhanced in &lt;code&gt;OnAutoWireViewModelChanged&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;simpleinjector&quot;&gt;SimpleInjector&lt;/h2&gt;
&lt;p&gt;To use simple injector with Xamarin Forms the only thing I had to do was to add the SimpleInjector NuGet package to the project.&lt;/p&gt;
&lt;p&gt;Hope this helps.&lt;/p&gt;</content:encoded></item><item><title>Ensure public API surface using ApprovalTests</title><link>https://marcduerst.com/blog/ensure-public-api-surface-using-approval-tests/</link><guid isPermaLink="true">https://marcduerst.com/blog/ensure-public-api-surface-using-approval-tests/</guid><description>One of the things that made me think for some time is “How can I ensure my public REST-API does not change by accident?”.</description><pubDate>Sat, 16 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the things that made me think for some time is “How can I ensure my public REST-API does not change by accident?”.&lt;/p&gt;
&lt;h1 id=&quot;why&quot;&gt;Why&lt;/h1&gt;
&lt;p&gt;With todays IDE’s we have very powerfull automatic refactorings which is cool. The downside is that we easily can refactor a large pile of code what can affect the public API’s without the developer notice it.&lt;/p&gt;
&lt;p&gt;When my public API’s (for example a REST-API’s my backend offers to partner companies) changes without notice it will be found very late the software development lifecycle. Worst case: after the release. This will result in a lot of work (and cost) for everybody involved.&lt;/p&gt;
&lt;h1 id=&quot;the-idea&quot;&gt;The idea&lt;/h1&gt;
&lt;p&gt;So “Where is the problem?” you may ask: “Just write a bunch of unit-tests!”. The problem with this is that with the powerfull refactorings we usualy also refactor the unit-test code in one go. So the unit-test never becomes red even if we changed the public API. Therefore plain unit-tests are useless for this kind of tests.&lt;/p&gt;
&lt;p&gt;We need something that does not get refactored automatically when we use automatic refactorings.&lt;/p&gt;
&lt;p&gt;What I came up with is using &lt;a href=&quot;1&quot;&gt;ApprovalTests&lt;/a&gt; to dump the relevant data a in a approved-file (aka &lt;em&gt;expectation file&lt;/em&gt;). This becomes our exectation of the unit-test result. The approval files don’t get changed by refactorings.&lt;/p&gt;
&lt;p&gt;When they change I as a developer have to approve the new content manually (with the help of my diff tool) and therefore get noticed by my unit-test suite that something in the API changed.&lt;/p&gt;
&lt;h1 id=&quot;how&quot;&gt;How&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;1&quot;&gt;ApprovalTests&lt;/a&gt; implementations are availlable for all major platoforms. For .Net you can install &lt;a href=&quot;2&quot;&gt;this Nuget package&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To test may REST-API’s I basically call action methods of my WebAPI controllers, serialize the output as Json and verify it using Approvals.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;UseReporter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;DiffReporter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PersonControllerTests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IPersonRepository&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; personRepo&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; A.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Fake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IPersonRepository&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PersonController&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; controller&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PersonControllerTests&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        controller &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PersonController&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(personRepo);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Fact&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Task&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; GetDetails_Success_MustReturnObject&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // Arrange&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; personId&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Guid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;51bd89eb-5ae6-4cfe-954a-f3f6a51352ab&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // Act&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; result&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; controller.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GetDetails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(personId)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // Assert&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        Approvals.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;VerifyJson&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(JsonConvert.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SerializeObject&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(result));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To enhace this one can also store the verb’s and URL’s. To do so you can wrap the above &lt;code&gt;result&lt;/code&gt; in an anonymous object where you store additional information and serialize all of that into Json and approve it. It would be recommeded to implement a helper for doing this.&lt;/p&gt;
&lt;h1 id=&quot;alternative-idea&quot;&gt;Alternative idea:&lt;/h1&gt;
&lt;p&gt;For REST-API’s an alternative idea is to generete the Swagger.json file you normaly need anyway and store it in your repo. Write a unit-tests that compares a freshly generated Swagger.json to the existing one. This would need some more advanced testing code / helpers but result in verify every aspect of the public API (Url’s, HTTP-Verbs, data-structures, supported headers, query-parameters, etc.)&lt;/p&gt;</content:encoded></item><item><title>Mapping with Dictionary instead switch</title><link>https://marcduerst.com/blog/mapping-with-dictionary-instead-switch/</link><guid isPermaLink="true">https://marcduerst.com/blog/mapping-with-dictionary-instead-switch/</guid><description>Recently I read the book “Refactoring: Improving the Design of Existing Code (2nd Edition)” by Martin Fowler (here…). A great book I highly recommend. Beside...</description><pubDate>Wed, 30 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I read the book “Refactoring: Improving the Design of Existing Code (2nd Edition)” by Martin Fowler (&lt;a href=&quot;https://martinfowler.com/books/refactoring.html&quot;&gt;here…&lt;/a&gt;). A great book I highly recommend. Besides a lot of other useful informations and tips I started adapting to not use &lt;code&gt;switch&lt;/code&gt; statements for mapping-logic.&lt;/p&gt;
&lt;h2 id=&quot;why-not-using-switch&quot;&gt;Why not using Switch?&lt;/h2&gt;
&lt;p&gt;The point is that a &lt;code&gt;switch&lt;/code&gt; statement can do a lot more things then just mapping value. From my own experience I can confirm that regularly a switch’s &lt;code&gt;case&lt;/code&gt; branch does more then one thing. More then just map value A to B. This leads in side-effects of the mapping logic. Further more the code does not clearly show its intent anymore, is harder to read, refactor and extend.&lt;/p&gt;
&lt;p&gt;So we look for a better solution for mapping values. A solution that does only map values from A to B and no other logic can be placed into. It should show clearly that it only does a simple value-mapping.&lt;/p&gt;
&lt;p&gt;That’s where dictionaries come into the play.&lt;/p&gt;
&lt;h2 id=&quot;dictionaries&quot;&gt;Dictionaries&lt;/h2&gt;
&lt;p&gt;Dictionary is a collection data-stucture that host key-value items. One can access values very fast by its indexer; the key. They have an optimized and short syntax to do exactly this. If you don’t use delegates as the value you can not add logic. Its a simple &lt;em&gt;value translation table&lt;/em&gt;. So the intent should be very clear.&lt;/p&gt;
&lt;h2 id=&quot;example&quot;&gt;Example&lt;/h2&gt;
&lt;p&gt;Let’s map an enum value to a string (can be anything else). Here is the enum:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; enum&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Gender&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    Female&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    Male&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    Other&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Map value using a switch statement:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;string MapGenderToString(Gender gender)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    swtich (gender)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        case Gender.Female:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            return &quot;Woman&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        case Gender.Male:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            return &quot;Man&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        case Gender.Other:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            return &quot;Other&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        default:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            throw new ArggumentRangeException();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem here is that you can easily add any kind of logic (code) within one or more &lt;code&gt;case&lt;/code&gt; blocks. This would be a code-smell as written before.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Map value using a dictionary:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;string MapGenderToString(Gender gender)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    var mapping = new Dictionary&amp;#x3C;Gender, string&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        { Gender.Female, &quot;Woman&quot; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        { Gender.Male, &quot;Man&quot; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        { Gender.Other, &quot;Other&quot; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return mapping[gender];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s way harder – but not impossible – to missuse this mapping code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bonus value:&lt;/strong&gt; Because the mapping is so simple one whould not even need an extra method for this. The mapping could be defined as a readonly-field and used directly in the parent code.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PersonMapper&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;     private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; genderMapping &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Dictionary&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Gender&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        { Gender.Female, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Woman&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        { Gender.Male, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Man&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        { Gender.Other, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Other&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    public PersonDto &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MapPerson&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Person person) =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PersonDto&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            Gender&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; genderMapping[person.Gender],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hope this gives some inspiration. Let me know what you think about this.&lt;/p&gt;</content:encoded></item><item><title>Chapter 1: My journey in Clean Architecture and Domain Driven Design</title><link>https://marcduerst.com/blog/chapter-1-my-journey-in-clean-architecture-and-domain-driven-design/</link><guid isPermaLink="true">https://marcduerst.com/blog/chapter-1-my-journey-in-clean-architecture-and-domain-driven-design/</guid><description>Last year I’ve read several new books about software development. One of them was the book “Clean Architecture: A Craftsman’s Guide to Software Structure and...</description><pubDate>Sun, 22 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Last year I’ve read several new books about software development. One of them was the book “&lt;em&gt;&lt;a href=&quot;https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164&quot;&gt;Clean Architecture: A Craftsman’s Guide to Software Structure and Design&lt;/a&gt;&lt;/em&gt;” by Robert C. Martin (aka Uncle Bob).&lt;/p&gt;
&lt;p&gt;On the other hand I started to use more &lt;em&gt;Domain Driven Design&lt;/em&gt; (DDD) practice on my day-job. I read about &lt;em&gt;DDD&lt;/em&gt; already several times in the past but never got it really started.&lt;/p&gt;
&lt;p&gt;On one hand I like to practice DDD but even more I was hungry to do a &lt;em&gt;Clean Architecture&lt;/em&gt; journey and give it a try. What I needed was a peace of software to get started with. Lucky my I had a web application that needed some love anyway. Voila: my journey was ready to start!&lt;/p&gt;
&lt;p&gt;In this multipart blog post I write what challenges I faced and what solutions I finally came up with.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chapters:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chapter 1: (this one) Intro and setting the stage&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marcduerst.com/blog/chapter-2-clean-architecture-domain-driven-design&quot;&gt;Chapter 2: Clean Architecture and DDD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marcduerst.com/blog/chapter-3-controllers&quot;&gt;Chapter 3: Controllers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marcduerst.com/blog/chapter-4-use-cases-interactors&quot;&gt;Chapter 4: Use-Cases &amp;#x26; Interactors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marcduerst.com/blog/chapter-5-entities-domain-events-and-policies&quot;&gt;Chapter 5: Entities &amp;#x26; Domain Events&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marcduerst.com/blog/chapter-6-presenters-view-models&quot;&gt;Chapter 6: Presenters &amp;#x26; View-Models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marcduerst.com/blog/chapter-7-drivers-data-access&quot;&gt;Chapter 7: Drivers &amp;#x26; Data Access&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marcduerst.com/blog/chapter-8-conclusion-and-final-words&quot;&gt;Chapter 8: Conclusion and final words&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-web-application&quot;&gt;The web application&lt;/h2&gt;
&lt;p&gt;The web application I liked to modernize is the one that run on &lt;a href=&quot;https://tauchbolde.ch&quot;&gt;https://tauchbolde.ch&lt;/a&gt;. It’s the website of my diving group. Beside some static content and some other diving calculation-gadgets it has two main domains (aka modules): &lt;em&gt;Diving events&lt;/em&gt;(&lt;em&gt;Events&lt;/em&gt; in short) and &lt;em&gt;Logbook&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;Events&lt;/em&gt; domain allows divers to create upcoming diving events/dives and register for them incl. building buddy-teams, place comments, download ICal files, etc. The &lt;em&gt;Logbook&lt;/em&gt; domain allows members to write articles about past events with image upload etc. Kind of a simple blog.&lt;/p&gt;
&lt;p&gt;The samples in this journey are from the &lt;em&gt;Logbook&lt;/em&gt; domain as this simple blog is way easier to understand than then diving stuff.&lt;/p&gt;
&lt;p&gt;The website is build using .Net Core 2.2, ASP.Net MVC Core 2.2 and Entity Framework Core 2.2. All the soure-code can be found &lt;a href=&quot;https://github.com/mduu/tauchbolde&quot;&gt;here on GitHub&lt;/a&gt;. The Azure DevOps pipelines are &lt;a href=&quot;https://dev.azure.com/tauchbolde-devops/tauchbolde-devops/_release?definitionId=1&amp;#x26;view=mine&amp;#x26;_a=releases&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;problems-with-the-old-architecture&quot;&gt;Problems with the old architecture&lt;/h2&gt;
&lt;p&gt;The old application was build like many common MVC application are: MVC-Controller uses repositories to load/save data and builds the view-model ad-hoc in the controller and triggers the view.&lt;/p&gt;
&lt;p&gt;As the logic parts had grown I moved them into what was called &lt;em&gt;domain services&lt;/em&gt; and therefore removed data-access from the MVC controllers.&lt;/p&gt;
&lt;p&gt;With the time some domain-services started to re-use other domain-services and cross-cutting general purpose services. If became less clear what depends on what and unit-testing these domain services became a challenge on its own.&lt;/p&gt;
&lt;p&gt;Read on about &lt;em&gt;Clean Architecture &amp;#x26; Domain Driven Design&lt;/em&gt; &lt;a href=&quot;https://marcduerst.com/blog/chapter-2-clean-architecture-domain-driven-design&quot;&gt;here…&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Chapter 2: Clean Architecture &amp; Domain Driven Design</title><link>https://marcduerst.com/blog/chapter-2-clean-architecture-domain-driven-design/</link><guid isPermaLink="true">https://marcduerst.com/blog/chapter-2-clean-architecture-domain-driven-design/</guid><description>As I already stated Clean Architecture was the main reason I started this journey. If you are seriously interested in reading more about Clean Architecture I...</description><pubDate>Sun, 22 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;clean-architecture&quot;&gt;Clean Architecture&lt;/h1&gt;
&lt;p&gt;As I already stated &lt;em&gt;Clean Architecture&lt;/em&gt; was the main reason I started this journey. If you are seriously interested in reading more about &lt;em&gt;Clean Architecture&lt;/em&gt; I kindly recommend &lt;a href=&quot;https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164&quot;&gt;Uncle Bob’s book&lt;/a&gt;. The book features several parts. One introduce the SOLID principals on architecture level while others focus more on the &lt;em&gt;Clean Architecture&lt;/em&gt; itself. The “problem” with the book is that does not have easy adoptable guidelines. There is some sample code but not in the form for general re-usage. So it leaves some room for interpretation – which I did.&lt;/p&gt;
&lt;p&gt;On &lt;a href=&quot;https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html&quot;&gt;this blogpost&lt;/a&gt; Uncle Bob summarized the core ideas behind the &lt;em&gt;Clean Architecture&lt;/em&gt; (&lt;em&gt;CA&lt;/em&gt;). Before continue here please read it first.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cleancoder.com/uncle-bob/images/2012-08-13-the-clean-architecture/CleanArchitecture.jpg&quot; alt=&quot;The Clean Architecture&quot;&gt;&lt;br&gt;
&lt;em&gt;Copyright by Rober C. Martin&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you look at the above diagram from Uncle Bob you’ll see two things.&lt;/p&gt;
&lt;p&gt;The “rings” or “layers”. An inner ring does not know anything about outer rings and outer rings only know the next inner ring. In the center there are the business entities. Uncle Bob leaves it open if you do &lt;em&gt;Domain Aggregates&lt;/em&gt; or some other kind of &lt;em&gt;business-objects&lt;/em&gt;. Then there are the use-cases from the business. This is where the “&lt;em&gt;dance of the entities&lt;/em&gt;” is orchestrated. In other architecture this is known as the application-layer.&lt;/p&gt;
&lt;p&gt;When you look at the bottom right there is a second diagram: The flow of control. At first I didn’t get this one while later I spent serious time thinking on how to implement something comes close to this flow in a MVC web application. More on this later.&lt;/p&gt;
&lt;p&gt;The nice thing about CA (and others like &lt;em&gt;The Onion Architecture&lt;/em&gt;) is that it nicely separates concerns and therefore dependencies. This leads to way easy writing of automated unit-tests which is a big deal from my point of view.&lt;/p&gt;
&lt;p&gt;I somewhere read that &lt;em&gt;CA&lt;/em&gt; can nicely be combined with &lt;em&gt;Domain Driven Design&lt;/em&gt; – it can act like a host to DDD so let’s quickly address DDD.&lt;/p&gt;
&lt;h1 id=&quot;domain-driven-design-ddd&quot;&gt;Domain Driven Design (DDD)&lt;/h1&gt;
&lt;p&gt;If you like to get quick intro to the core of DDD I can recommend the book &lt;em&gt;&lt;a href=&quot;https://www.infoq.com/minibooks/domain-driven-design-quickly/&quot;&gt;DDD Quickly&lt;/a&gt;&lt;/em&gt; by InfoQ freely available online. Another good but a little thicker book is &lt;em&gt;&lt;a href=&quot;https://www.amazon.com/Domain-Driven-Design-Distilled-Vaughn-Vernon/dp/0134434420&quot;&gt;Domain Driven Design Distilled&lt;/a&gt;&lt;/em&gt; by Vaughn Vernon.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How I see the big value of DDD:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The DDD principals puts the business-perspective back on the code. The same does CA. The goal is that we can see the main business values our app addresses in quickly in our code without the need of digging to tons of techie stuff first. It should be obvious for a reader what main business-needs the software addresses. Its why the software has the right to exist. Uncle Bob calls this “[&lt;em&gt;Screaming Architecture&lt;/em&gt;]”(&lt;a href=&quot;https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html&quot;&gt;https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;One of the nice things with DDD is that one build the core of the code around the business needs in a nice object-oriented manner.&lt;/p&gt;
&lt;p&gt;With these basics in place &lt;a href=&quot;https://marcduerst.com/blog/chapter-3-controllers&quot;&gt;let’s jump into my implementation …&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Chapter 3: Controllers</title><link>https://marcduerst.com/blog/chapter-3-controllers/</link><guid isPermaLink="true">https://marcduerst.com/blog/chapter-3-controllers/</guid><description>In CA a controller takes input, validates it and convert it to the format best used for the use-cases layer (especially the interactors).</description><pubDate>Sun, 22 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In CA a controller takes input, validates it and convert it to the format best used for the use-cases layer (especially the interactors).&lt;/p&gt;
&lt;p&gt;This is where I did the compromises and went away from &lt;em&gt;Clean Architecture&lt;/em&gt;. In my application the controllers are MVC-Controllers. They do the input-to-usecase-thing but also have to deliver the final &lt;code&gt;IActionResult&lt;/code&gt; (kind of the HTTP-Response). If I like to do a really clean architecture I need separate the web-stuff and the non-web-stuff for example by introducing a Use-Case-Controller (called by the MVC-Controller). I decided that this is so far will remain a web-application for the foreseeable future so I made the compromise to use the MVC-Controller as my &lt;em&gt;controller&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A simple controller-action in my application looks like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;HttpGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Authorize&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Policy&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; PolicyNames.RequireTauchboldeOrAdmin)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Task&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Publish&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Guid&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; publishLogbookEntry&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PublishLogbookEntry&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(id);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; result&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; mediator.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(publishLogbookEntry);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;result)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        ShowErrorMessage&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Fehler beim Publizieren des Logbucheintrages!&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    ShowSuccessMessage&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Logbucheintrag erfolgreich publiziert.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RedirectToAction&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Detail&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Logbook&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {id});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that this is a controller-action with no further output besides a success message so I don’t use presenters etc. More on presenters and view-models later on.&lt;/p&gt;
&lt;p&gt;What the above code does is create a use-case command object of type &lt;code&gt;PublishLogbookEntry&lt;/code&gt; which holds the data used for this simple use-case to publishing an article. In this case its just the ID of the &lt;code&gt;LogbookEntry&lt;/code&gt; to publish.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PublishLogbookEntry&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PublishLogbookEntry&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Guid&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; logbookEntryId&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        LogbookEntryId &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; logbookEntryId;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Guid&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LogbookEntryId&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The class implements the &lt;code&gt;IRequest&lt;/code&gt; interface of &lt;a href=&quot;https://github.com/jbogard/MediatR&quot;&gt;MediatR&lt;/a&gt;. MediatR is a in-process message-queue. It allows me to send requests to one recipients or broadcast notifications to multiple subscribers. I use it to decouple things further more. In this example the controller-action creates a &lt;code&gt;PublishLogbookEntry&lt;/code&gt; request and sends it using MediatR. The controller has not even a clue that there will be a use-case interactor or even a domain-entity. He just sends this request and expect a response from &lt;em&gt;someone&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The implementation of &lt;code&gt;ÌRequest&lt;/code&gt; means that this is a “request” object that gets sent to one receiver and returns a &lt;code&gt;bool&lt;/code&gt; result to the caller.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I try to implement as many classes as immutable classes as possible. This is why there is no setter on the &lt;code&gt;LogbookEntryId&lt;/code&gt; and it can only be set using the constructor and never be changed afterwards. For the “why immutable” you may read &lt;a href=&quot;https://blogs.msdn.microsoft.com/ericlippert/2007/11/13/immutability-in-c-part-one-kinds-of-immutability/&quot;&gt;this blog from Eric Lippert&lt;/a&gt; on &lt;em&gt;Immutability in C#&lt;/em&gt;. There will be other places in the code where I use newer C# language features to enforce immutability.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In addition to the use-case command object I often also implement a validator (see &lt;em&gt;Fluent Validations&lt;/em&gt;) for the command. These command validators get picked up by MediatR automatically (if configured correctly), validate the request object and return validation errors before any further processing of the command is done. These things are called &lt;em&gt;pipeline behavior&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s go one to one of the most important peaces of my implementation, the &lt;a href=&quot;https://marcduerst.com/blog/chapter-4-use-cases-interactors&quot;&gt;&lt;em&gt;Use-Cases &amp;#x26; Interactors&lt;/em&gt; …&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Chapter 4: Use Cases &amp; Interactors</title><link>https://marcduerst.com/blog/chapter-4-use-cases-interactors/</link><guid isPermaLink="true">https://marcduerst.com/blog/chapter-4-use-cases-interactors/</guid><description>In my architecture the use-case command objects get served by so called Use-Case Interactors. Technically these are MediatR ÌRequestHandler which handle the ...</description><pubDate>Sun, 22 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: screenshot-2019-09-22-at-11.47.12.png --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 1 image that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In my architecture the use-case command objects get served by so called &lt;em&gt;Use-Case Interactors&lt;/em&gt;. Technically these are MediatR &lt;code&gt;ÌRequestHandler&lt;/code&gt; which handle the use-case commands. Interactors orchestrate “the dance of the entities” as Uncle Bob says. This means that they do a mix of loading and saving entities from/to the persistence layer, call business logic using the entitiy-methods, calling other services, connect to external systems etc. They are orchestrators or moderators if you wish. Its one of the main parts for the &lt;em&gt;application layer&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I you look at solution explorer you immediately see what use-cases this application addresses. This way even the business and domain-exports understand the scope of the application. This is one of the really cool things.&lt;/p&gt;
&lt;p&gt;So let’s jump to a sample code of the use-case interactor which publishes a &lt;code&gt;LogbookEntry&lt;/code&gt; for public viewing:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;UsedImplicitly&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PublishLogbookEntryInteractor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IRequestHandler&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;PublishLogbookEntry&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ILogger&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;PublishLogbookEntryInteractor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;logger&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ILogbookEntryRepository&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; dataAccess&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PublishLogbookEntryInteractor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ILogger&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;PublishLogbookEntryInteractor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;logger&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ILogbookEntryRepository&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; dataAccess&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.dataAccess &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; dataAccess &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(dataAccess));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.logger &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; logger &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(logger));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Handle&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;PublishLogbookEntry&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CancellationToken&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cancellationToken&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (request &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(request));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        logger.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;LogInformation&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Publish Logbook-Entry {logbookEntryId}&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, request.LogbookEntryId);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; logbookEntry&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; dataAccess.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;FindByIdAsync&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(request.LogbookEntryId);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (logbookEntry &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            logger.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;LogError&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Logbook-Entry {logbookEntryId} not found&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, request.LogbookEntryId);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        try&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            logbookEntry.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Publish&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; dataAccess.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;UpdateAsync&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(logbookEntry);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            logger.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;LogInformation&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Logbook-Entry {logbookEntryId} published successfull.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, request.LogbookEntryId);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        catch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Exception&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ex&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            logger.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;LogError&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ex, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Error publishing logbook entry {logbookEntryId} {logbookEntryTitle}&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, logbookEntry.Id, logbookEntry.Title);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The interactor implements &lt;code&gt;ÌRequestHandler&lt;/code&gt; so MediatR use them to handle &lt;code&gt;PublishLogbookEntry&lt;/code&gt; request that return a &lt;code&gt;bool&lt;/code&gt; result.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;code&gt;private readonly&lt;/code&gt; fields that can be set only within the constructor of the class and therefore are immutable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The constructor parameters normally get injected by IoC container but in the unit-tests fakes are provided for them (see &lt;em&gt;Dependency Inversion&lt;/em&gt; principal).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The constructor implementation uses C# 7 &lt;em&gt;throw expressions&lt;/em&gt; to check if the value is not null. I also use R# annotations like &lt;code&gt;[NotNull[]&lt;/code&gt; and &lt;code&gt;[UsedImplicitly]&lt;/code&gt;. These annotations help R# to help you by hinting where you might get a null-reference exception if you do not check for &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Another thing I got from &lt;em&gt;Clean Architecture&lt;/em&gt; is to make as much as possible accessible only &lt;code&gt;internal&lt;/code&gt;. Everything that I declare &lt;code&gt;public&lt;/code&gt; is considered an external API that needs to be supported and therefore can not easily change. When everything in a assembly is &lt;code&gt;public&lt;/code&gt; its a sign of a code-smell. Regarding Uncle Bob hiding things by not making them public is the biggest advantage for object-oriented programming (OOP).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we have seen the application layer – or &lt;em&gt;Application Business Rules&lt;/em&gt; as it is called &lt;em&gt;CA&lt;/em&gt; – its time to go to the &lt;em&gt;Enterprise Business Rules&lt;/em&gt;. Let’s look at the &lt;em&gt;Entities&lt;/em&gt; and &lt;em&gt;Domain Events&lt;/em&gt; &lt;a href=&quot;https://marcduerst.com/blog/chapter-5-entities-domain-events-and-policies&quot;&gt;here …&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Chapter 5: Entities, Domain Events and Policies</title><link>https://marcduerst.com/blog/chapter-5-entities-domain-events-and-policies/</link><guid isPermaLink="true">https://marcduerst.com/blog/chapter-5-entities-domain-events-and-policies/</guid><description>Most interactors call one or more methods on the entities. These entities are the “business objects” and the methods implement the “business logic”. In a eve...</description><pubDate>Sun, 22 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;entities&quot;&gt;Entities&lt;/h1&gt;
&lt;p&gt;Most &lt;em&gt;interactors&lt;/em&gt; call one or more methods on the entities. These entities are the “business objects” and the methods implement the “business logic”. In a event-sourced system the entities are known as domain-aggregates.&lt;/p&gt;
&lt;p&gt;An entities method should only do things on the local entity. It must not depend on other entities (aka aggregates). It may use other services that get pass into the method using a parameter but most if the time this is a sign for a code-smell. For such tasks we will use domain-events and policies (see below).&lt;/p&gt;
&lt;p&gt;In the above sample the following line is the meat:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;logbookEntry.Publish();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;LogbookEntry&lt;/code&gt; entity looks as following.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LogbookEntry&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;EntityBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; bool&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IsPublished&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Publish&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (IsPublished) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        IsPublished &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        RaiseDomainEvent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LogbookEntryPublishedEvent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Id));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;See full &lt;a href=&quot;https://github.com/mduu/tauchbolde/blob/develop/src/Tauchbolde.Domain/Entities/LogbookEntry.cs&quot;&gt;source-code&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;Publish()&lt;/code&gt; method first checks if the &lt;code&gt;LogbookEntry&lt;/code&gt; is already published because then nothing needs to be done anymore. If not the &lt;code&gt;IsPublished&lt;/code&gt; flag will be set and a &lt;em&gt;domain event&lt;/em&gt; &lt;code&gt;LogbookEntryPublishedEvent&lt;/code&gt; will be raised to indicate what just happened to other parts of the application (more on this later).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;IsPublished&lt;/code&gt; as an &lt;em&gt;internal&lt;/em&gt; setter. This is to simplify writing unit-tests. My unit-test assembly is listed as a so called &lt;em&gt;friendly assembly&lt;/em&gt; to the domain assembly so internals are visible to unit-tests too.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;EntityBase&lt;/code&gt; base-class features the `Ìd“ property as well as the storage of the &lt;em&gt;uncommitted&lt;/em&gt; domain-events. See &lt;a href=&quot;https://github.com/mduu/tauchbolde/blob/develop/src/Tauchbolde.SharedKernel/EntityBase.cs&quot;&gt;here&lt;/a&gt; for soure-code.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;domain-events&quot;&gt;Domain Events&lt;/h1&gt;
&lt;p&gt;A domain event (see DDD) indicates that something important happened on a entity (aka domain aggregate). They are where the &lt;em&gt;open/close principals&lt;/em&gt; gets into the play. Some call them &lt;em&gt;extensibility points&lt;/em&gt;. It’s the way entities can communicate with the outer world.&lt;/p&gt;
&lt;p&gt;The domain event &lt;code&gt;LogbookEntryPublishEvent&lt;/code&gt; gets broadcasted using MediatR &lt;strong&gt;after&lt;/strong&gt; the data-access did persist the entitiy. Because they are broadcasted to the in-process messaging zero to many subscribers can consume them and do various others things. Normally these things are not so closely related to the previous domain entity logic or need to interact with more then just the one current entity.&lt;/p&gt;
&lt;p&gt;In our example the domain event &lt;code&gt;LogbookEntryPublishedEvent&lt;/code&gt;looks like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LogbookEntryPublishedEvent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;DomainEventBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Guid&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LogbookEntryId&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LogbookEntryPublishedEvent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Guid&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; logbookEntryId&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        LogbookEntryId &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; logbookEntryId;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you may have noted I have a baseclass for my domain events call &lt;code&gt;DomainEventBase&lt;/code&gt;. This just inherit from &lt;code&gt;INotification&lt;/code&gt; records the time when the event happened:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; abstract&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; DomainEventBase&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;INotification&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; DateTime&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; DateOccurred&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; DateTime.UtcNow;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In a event-sourced application the donain-event would then be stored in the event-store and projectors will listen on then to to update their read-stores (eg. SQL tables). In my application I do &lt;strong&gt;not&lt;/strong&gt; do event-sourcing so the domain-events serve &lt;em&gt;only&lt;/em&gt; for notifying other building blocks that can do further processing. Policies are such building building blocks.&lt;/p&gt;
&lt;p&gt;After we have the interactors in place which do the “dance of the entities” as well as having the entities with the business logic and the domain-event it’s time to move on what happens after the domain-events are published.&lt;/p&gt;
&lt;h1 id=&quot;policies&quot;&gt;Policies&lt;/h1&gt;
&lt;p&gt;Policies are application-logic classes (in the application layer) that listen to domain-events. Policy then can do additional work that is not directly part to the previous domain method but to its result (the domain-event). The do work with other services or entities/aggregates outside of the initial entity/aggregate. Entities/aggregates should depend on other entities/aggregates.&lt;/p&gt;
&lt;p&gt;To do their stuff Policies can access all of the application- and domain-level infrastructure – just like interactor can. This means they can load and update domain entities using repository-interfaces, call domain entity methods to execute other business-logic or they can use other application level services.&lt;/p&gt;
&lt;p&gt;In our sample for publishing logbook entries we have two policies in place that listen to the &lt;code&gt;LogbookEntryPublishedEvent&lt;/code&gt; domain-event.&lt;/p&gt;
&lt;p&gt;The first one is &lt;code&gt;LogTelemetryLogbookEntryPublishedPolicy&lt;/code&gt; which does only one little thing: it uses the &lt;code&gt;ITelemetryService&lt;/code&gt; application-service to record the publish use-case as a telemetry-event. In my case they get submitted to &lt;em&gt;Azure AppInsights&lt;/em&gt; for further logging and analytics.&lt;/p&gt;
&lt;p&gt;The second policy is a little bit more interesting: &lt;code&gt;PublishNewLogbookEntryNotificationPolicy&lt;/code&gt;. The job of the policy is to publish &lt;em&gt;Notification&lt;/em&gt;‘. Notifications – in my domain – means a notification to users about something that happened. These notifications get picked up later on and an email newsletter is generated and sent every user.&lt;/p&gt;
&lt;p&gt;Let’s take a look at this policy:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;UsedImplicitly&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PublishNewLogbookEntryNotificationPolicy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;INotificationHandler&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;LogbookEntryPublishedEvent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IDiverRepository&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; diverRepository&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ILogbookEntryRepository&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; logbookEntryRepository&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; INotificationPublisher&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; notificationPublisher&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PublishNewLogbookEntryNotificationPolicy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IDiverRepository&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; diverRepository&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ILogbookEntryRepository&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; logbookEntryRepository&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;INotificationPublisher&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; notificationPublisher&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.diverRepository &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; diverRepository &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(diverRepository));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.logbookEntryRepository &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; logbookEntryRepository &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(logbookEntryRepository));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.notificationPublisher &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; notificationPublisher &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(notificationPublisher));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Task&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Handle&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;LogbookEntryPublishedEvent&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; notification&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CancellationToken&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cancellationToken&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (notification &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(notification));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; recipients&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; diverRepository.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GetAllTauchboldeUsersAsync&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; logbookEntry&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; logbookEntryRepository.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;FindByIdAsync&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(notification.LogbookEntryId);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; author&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; diverRepository.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;FindByIdAsync&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(logbookEntry.OriginalAuthorId);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; message&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; $&quot;Neuer Logbucheintrag &apos;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;logbookEntry&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Title&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos; von &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;author&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Realname&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; notificationPublisher.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;PublishAsync&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            NotificationType.NewLogbookEntry,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            message,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            recipients,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            relatedLogbookEntryId&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: notification.LogbookEntryId);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The policy uses the &lt;code&gt;IDiverRepository&lt;/code&gt; and &lt;code&gt;ILogbookEntryRepository&lt;/code&gt; for accessing the entities it needs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The policy gets all the data it needs in the &lt;code&gt;notification&lt;/code&gt; parameter which is the domain-event. In this sample it gets the &lt;code&gt;notification.LogbookEntryId&lt;/code&gt; which it uses to load details about the &lt;code&gt;LogbookEntry&lt;/code&gt; from the database.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;INotificationPublisher.PublishAsync()&lt;/code&gt; is used to publish the notification to all interested users. Note that &lt;code&gt;INotificationPublisher&lt;/code&gt; is general application-service which gets injected into the policy as a constructor parameter.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After we set up the basic stuff its time to move to the most tricky part to fiddle out how to do it: &lt;a href=&quot;https://marcduerst.com/blog/chapter-6-presenters-view-models&quot;&gt;Presenters and View-Models&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title>Chapter 6: Presenters &amp; View models</title><link>https://marcduerst.com/blog/chapter-6-presenters-view-models/</link><guid isPermaLink="true">https://marcduerst.com/blog/chapter-6-presenters-view-models/</guid><description>So far we covered the more command/write-side focused use-cases. It was pretty straight forward to implement this in a Clean Architecture fashion. What reall...</description><pubDate>Sun, 22 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So far we covered the more command/write-side focused use-cases. It was pretty straight forward to implement this in a &lt;em&gt;Clean Architecture&lt;/em&gt; fashion. What really got me think for a longer time (days or weeks) was the kind of use-cases where real user-output (eg. HTML) must be produced. This is the part where the &lt;em&gt;Presenters&lt;/em&gt; come into the play.&lt;/p&gt;
&lt;p&gt;If we take a look again at the &lt;a href=&quot;https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html&quot;&gt;control-flow in Uncle Bobs diagram&lt;/a&gt; at the beginning we see the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Controller calls the interactor using the input-port.&lt;/li&gt;
&lt;li&gt;Interactor calls the output-port.&lt;/li&gt;
&lt;li&gt;Presenter implements the output-port and renders things to the UI.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This means that a presenter can render stuff on its own to “the user-interface”. This is not how standard MVC works. In standard MVC we have the following flow.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Controller gets the user-input.&lt;/li&gt;
&lt;li&gt;Controller coordinates some kind of logic to do things.&lt;/li&gt;
&lt;li&gt;Controller returns a action result like a view result with the view-model needed to render the view.&lt;/li&gt;
&lt;li&gt;The ASP.Net pipelines fires the view-engine with the viewname and view-model from the view-result &lt;strong&gt;after&lt;/strong&gt; the controller-action was finished.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Hmm… so how to bring these worlds closer to each other. I know that Uncle Bob would not like to use standard MVC at all because it highly couples our overall architecture and dependencies to a framework we don’t have control over it. Regarding Uncle Bub, even the ASP.Net MVC part of the application should be an implementation detail that does not affect your architecture.&lt;/p&gt;
&lt;p&gt;I, on the other hand, have a existing MVC application and I like to use MVC as it was thought by its inventors for several reasons. First one is that if other developers join they at least know the basics. Other reason is documentation, communities and general help.&lt;/p&gt;
&lt;p&gt;Maybe one day I find the time to have a closer look at frameworks like &lt;em&gt;Nancy&lt;/em&gt; where I think I am more free with these architectural decisions.&lt;/p&gt;
&lt;p&gt;So again, how can I get things closer to &lt;em&gt;Clean Architecture&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;I did some googling and found a few people thought about this already. &lt;em&gt;Plainionist&lt;/em&gt; wrote a really nice series of article about this &lt;a href=&quot;http://www.plainionist.net/Implementing-Clean-Architecture-Controller-Presenter/&quot;&gt;here&lt;/a&gt;. Another nice thread I found on &lt;a href=&quot;https://stackoverflow.com/questions/50077826/clean-architecture-how-to-implement-presenters-in-mvc/50084079?noredirect=1#comment101316352_50084079&quot;&gt;here&lt;/a&gt; Stack-Overflow and one &lt;a href=&quot;https://codereview.stackexchange.com/questions/148809/a-button-as-a-clean-architecture-plugin&quot;&gt;here&lt;/a&gt; on CodeReviews.&lt;/p&gt;
&lt;p&gt;Regarding the control-flow we like to get this: &lt;em&gt;controller-interactor-presenter&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 1:&lt;/strong&gt; The controller gets the interactor result and create a view-model and returns the view. This will &lt;strong&gt;not&lt;/strong&gt; result in the control flow as of &lt;em&gt;Clean Architecture&lt;/em&gt; because no output-ports and presenters are used at all. The flow would be &lt;em&gt;controller-interactor-controller&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 2:&lt;/strong&gt; The controller gets the interactor result and forwards it to a presenter which builds and returns the view-model to the controller so the controller can return a view based on the presenters view-model. This is also &lt;strong&gt;not&lt;/strong&gt; the &lt;em&gt;Clean Architecture&lt;/em&gt; control-flow as its &lt;em&gt;controller-interactor-controller-presenter-controller&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 3:&lt;/strong&gt; The controller triggers the interactor and provide the presenter as the output port. The interactor then calls the presenter which builds the view-model. Finally the controller gets the view-model from the presenter and returns the view. Again its not exactly the &lt;em&gt;Clean Architecture&lt;/em&gt; control-flow: &lt;em&gt;controller-interactor-presenter-controller&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 4:&lt;/strong&gt; Like option 3 but split controller into MVC- and Clean-Architecture-controller. This would result in the flow &lt;em&gt;MVCcontroller-controller-interactor-presenter-MVCcontroller&lt;/em&gt;. Again not quite the &lt;em&gt;Clean Architecture&lt;/em&gt; way. But if we remove the technical &lt;em&gt;MVC-Controllers&lt;/em&gt; from the above equation we are in the green zone of &lt;em&gt;Clean Architecture&lt;/em&gt;. I guess Uncle Bob would also like this because the controller-logic is split away from the MVC-Framework and therefore its dependency.&lt;/p&gt;
&lt;p&gt;Why don’t we get the exact &lt;em&gt;Clean Architecture&lt;/em&gt; flow? Its because we use MVC where we have to build a view and return the view to the framework which finally renders the HTML. This means we don’t have a self-containing render-flow. At least not if we stick to the MVC framework and therefore can not freely control the flow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So what did I choose?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I like to go close with &lt;em&gt;Clean Architecture&lt;/em&gt; but don’t do too much extra work. So I went with … tatarataaa … &lt;strong&gt;Option 3&lt;/strong&gt; (with one eye to option 4 – maybe one day I go for 4).&lt;/p&gt;
&lt;p&gt;The next question regarding presenters was:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to inject the presenter into the interactor?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I basically see two options here:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 1:&lt;/strong&gt; Inject the output-port (eg. presenter) using a interactor constructor parameter (constructor injection).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 2:&lt;/strong&gt; Pass the output-port (eg. presenter) to the input-port into the interactor.&lt;/p&gt;
&lt;p&gt;The advantage of the first option is that you register the presenter as the output-port implementation with your DI and let the DI inject it. This way the controller does only know the presenters interface to get the view-model or the view out of it.&lt;/p&gt;
&lt;p&gt;The advantage of option 2 is that one can pass different output-port implementations to the same interactor depending where the interactor is used. This increase the re-usability of the interactor.&lt;/p&gt;
&lt;p&gt;What did I choose? I switched forth and back between these options but finally decided for option 2 because the very same application instance may not only host MVC- but also WebAPI controllers in the future. Using option 2 I can re-use the interactors for my REST-API and for my HTML-App. The only difference is that I pass in another output-port implementation. MVC-Presenter or JSON-Resenter.&lt;/p&gt;
&lt;p&gt;With the stage set on how to implement &lt;em&gt;Clean Architecture&lt;/em&gt; output-ports and presenters let’s have a look at the code I came up:&lt;/p&gt;
&lt;p&gt;First the controller-action to renders the detail page of a &lt;code&gt;LogbookEntry&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Task&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Detail&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Guid&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; presenter&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MvcLogbookDetailsOutputPort&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(relativeUrlGenerator, logbookDetailsUrlGenerator);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; interactorResult&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; mediator.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; GetLogbookEntryDetails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(id, presenter, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; GetAllowEdit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;interactorResult.IsSuccessful)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        ShowErrorMessage&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Fehler beim laden der Daten des Logbucheintrages!&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; View&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(presenter.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GetViewModel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;First the MVC-specific presenter is created including all the dependencies the presenter needs. I’m thinking of changing this so the presenter get created and injected into the controller using DI using constructor injection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The presenter implements the interactors output-port.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The interactor-command (aka &lt;em&gt;interactor input&lt;/em&gt;) is sent including a reference to the presenter as the output-port.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Basic error handling is done based on the interactor result.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally the controller asks the presenter for the view-model and returns a view. I am thinking if I should move the &lt;code&gt;View()&lt;/code&gt; statement to the presenter so the presenter will not only return a view-model but an entire view. This would take further UI-logic away from the controller and move it to the presenter.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s see how to presenter looks like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MvcLogbookDetailsOutputPort&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ILogbookDetailOutputPort&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IRelativeUrlGenerator&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; relativeUrlGenerator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ILogbookDetailsUrlGenerator&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; detailsUrlGenerator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        private&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LogbookDetailViewModel&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; viewModel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MvcLogbookDetailsOutputPort&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IRelativeUrlGenerator&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; relativeUrlGenerator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ILogbookDetailsUrlGenerator&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; detailsUrlGenerator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.relativeUrlGenerator &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; relativeUrlGenerator &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.relativeUrlGenerator));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.detailsUrlGenerator &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; detailsUrlGenerator &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(detailsUrlGenerator));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Output&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GetLogbookEntryDetailOutput&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; interactorOutput&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (interactorOutput &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(interactorOutput));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            viewModel &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LogbookDetailViewModel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                interactorOutput.AllowEdit,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                interactorOutput.LogbookEntryId,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                interactorOutput.Title,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                interactorOutput.IsFavorite,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                interactorOutput.CreatedAt.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ToStringSwissDateTime&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LogbookDetailViewModel&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; GetViewModel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; viewModel;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The presenter implements the &lt;code&gt;ILogbookDetailOutputPort&lt;/code&gt; by implementing the &lt;code&gt;Output()&lt;/code&gt; method with the signature as defined by the output-port. Note that the interactors only know and depend on the output-port interface. He doesn’t know who implements it nor that there are presenters or even view-models at all.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The view-model can be retrieved from the presenter using get &lt;code&gt;GetViewModel()&lt;/code&gt; method.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The presenter converts the output from the interactor to a view-model so view view has an easy job. This means that the presenter converts complex objects to with basic data-types. In the above example you see that &lt;code&gt;DateTime&lt;/code&gt; types get converted into strings so the views don’t need to do such conversions. More complex views get an more specialized view-model so the presenter for example builds multiple lists based on one interactor output. As said: the view should have as less logic as possible. Address render-logic in the presenter if possible.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s continue &lt;a href=&quot;https://marcduerst.com/blog/chapter-7-drivers-data-access&quot;&gt;here …&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Chapter 7: Drivers &amp; Data Access</title><link>https://marcduerst.com/blog/chapter-7-drivers-data-access/</link><guid isPermaLink="true">https://marcduerst.com/blog/chapter-7-drivers-data-access/</guid><description>Regarding Robert C. Martin, technical subsystems like storage, user-interface, external systems etc. are an implementation detail what should not bleed into ...</description><pubDate>Sun, 22 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;drivers&quot;&gt;Drivers&lt;/h1&gt;
&lt;p&gt;Regarding Robert C. Martin, technical subsystems like storage, user-interface, external systems etc. are an implementation detail what should not bleed into your application logic. Put them behind a nice interface and implement them in the most outer ring: &lt;em&gt;Framework &amp;#x26; Drivers&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To do so my project has the &lt;em&gt;Drivers&lt;/em&gt; solution folder. By the time of writing you find my implementations of database access (SQL with EF Core), image processing, email delivery and blob storage in here.&lt;/p&gt;
&lt;p&gt;Each of these assemblies cover a topic by implementing their interfaces agains a concrete technology. If I like to use other technology to drive a topic in the future I simply replace these assemblies with the new implementations.&lt;/p&gt;
&lt;h1 id=&quot;data-access&quot;&gt;Data-Access&lt;/h1&gt;
&lt;p&gt;A few words on the data-access. I’ve implemented the SQL data-access using &lt;em&gt;Entity Framework Core&lt;/em&gt;. I decided to not do another set of classes for the data-entities as they would be a 1:1 copy so far and I would need a ton of mapping code again.&lt;/p&gt;
&lt;p&gt;Instead I put the mapping definitions of my entities into the data-access. I think Uncle Bob would not want this.&lt;/p&gt;
&lt;p&gt;This may change when I go more into DDD style domain “aggregates” instead of relational entities. So far I did not have to need to change this.&lt;/p&gt;
&lt;p&gt;I’m also thinking to move away from SQL to Azure Cosmos DB (MongoDB for local development). The main problem for this move is the ASP.Net Identity for which I used the standard EF Core implementation so far. I have to port this over from EF Core. Maybe Microsoft will provide a CosmosDB implementation one day.&lt;/p&gt;
&lt;p&gt;The other issue with other database then SQL-Server is that for this project I have a very limited monthly budget and the SQL-Server is by way the cheapest option I found on Azure. $5/month while all other options I found where starting at $30/month.&lt;/p&gt;
&lt;p&gt;One option I found which is extremely cheap (1-2 cents/GB/month). It first sound strange but Azure Storage. But if I move over to complete aggregates I could store them in JSON files/blobs. The only constrains would be complex queries but as I don’t have big-data this may be an option for persisting my data.&lt;/p&gt;
&lt;p&gt;Let’s head over to my final thoughts and conclusions &lt;a href=&quot;https://marcduerst.com/blog/chapter-8-conclusion-and-final-words&quot;&gt;here …&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Chapter 8: Conclusion and final words</title><link>https://marcduerst.com/blog/chapter-8-conclusion-and-final-words/</link><guid isPermaLink="true">https://marcduerst.com/blog/chapter-8-conclusion-and-final-words/</guid><description>I’ve spent a lot of time exploring these topics over the last months. I hacked in the subway every day and rack ones brain after kids where in bed. I’m quite...</description><pubDate>Sun, 22 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve spent a lot of time exploring these topics over the last months. I hacked in the subway every day and rack ones brain after kids where in bed. I’m quite happy with the result but I also see room for improvement here and there.&lt;/p&gt;
&lt;p&gt;The nice thing about &lt;em&gt;Clean Architecture&lt;/em&gt; (and others) is that they push you to do small separated peaces that do only one thing (separation of concerns) and to decouple thinks. Further more one does not only decouple but also organize them into layers the way that inner layers only know the general interface but not the concrete implementation.&lt;/p&gt;
&lt;p&gt;This results in excellent test-ability and one can easily replace an implementation without changing the overall concept.&lt;/p&gt;
&lt;p&gt;The nice thing about &lt;em&gt;Domain Driven Design&lt;/em&gt; is that the business logic and flows are put into the center and that one builds a “domain model” out of it in a nice object-oriented fashion. We no longer have dumb objects that gets manipulated by services all over which are more procedural programming like.&lt;/p&gt;
&lt;p&gt;The overall architecture I came up with in the sample application uses the same building blocks and clearly defined flows for all use-cases. I don’t have these strange service-dependencies all over.&lt;/p&gt;
&lt;p&gt;I am also forced to think more about the business needs of a use-case. For example I need a use-case to start with. I need to think about how things are named in business terms (entities, entity-methods). This builds the ubiquitous between the business and the techs.&lt;/p&gt;
&lt;p&gt;On the other hand this kind of architecture leads in more lines of code. But I think its worth it!&lt;/p&gt;
&lt;p&gt;… at least if the application not only a trivial CRUD app but has business flows / logic.&lt;/p&gt;
&lt;p&gt;Thanks for reading. Cheers!&lt;/p&gt;</content:encoded></item><item><title>Update SQL database using EF Core and Azure DevOps</title><link>https://marcduerst.com/blog/update-sql-database-using-ef-core-and-azure-devops/</link><guid isPermaLink="true">https://marcduerst.com/blog/update-sql-database-using-ef-core-and-azure-devops/</guid><description>If you write an app you probably need a way to store data. If you do it using a SQL Database (eg. SQL-Server) you need a way to change your Database-Schema s...</description><pubDate>Mon, 08 Jul 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you write an app you probably need a way to store data. If you do it using a SQL Database (eg. SQL-Server) you need a way to change your Database-Schema sooner then later.&lt;/p&gt;
&lt;p&gt;There are several options on how to do this in the Microsoft eco-system. Here I describe a very easy and simple way on how I do it for my personal project over at &lt;a href=&quot;https://tauchbolde.ch&quot;&gt;https://tauchbolde.ch&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;goal&quot;&gt;Goal&lt;/h2&gt;
&lt;p&gt;First of all my app is a ASP.Net Core MVC 2.2 app using EF Core 2.2 with SQL-Server. More precisely with Azure SQL-Server. The application is hosted on Azure AppService. I use Azure DevOps to fully automate my build and release pipeline.&lt;/p&gt;
&lt;p&gt;My goal was to automatically run the schema-migration as part of my automated deployment. The solution should be straight forward and transparent. It also should not need much of custom code.&lt;/p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;/h2&gt;
&lt;p&gt;I’m using EF Core’s Migrations to add migrations as soon as my schema needs to change. Normally I commit this migration together with my modified ORM model classes. Migrations are generated and added to the project using the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dotnet ef migrations add&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These migrations can be run on the command line using the EF CLI command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dotnet ef database update&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All pretty standard so far.&lt;/p&gt;
&lt;p&gt;Instead of running the above commands when deploying and hope they will succeed I like to do it more SQL-like and more transparent. Therefore I maintain one single SQL-Script that updates any schema-version to the latest version.&lt;/p&gt;
&lt;p&gt;Such an SQL-Script can easily be tested locally or on test-servers and with different datasets. If something goes wrong on production system’s migration we can fix the SQL-Script manually and are good without building a new software package.&lt;/p&gt;
&lt;p&gt;Lucky me EF Core has this feature built into. I use a command line like this to generate the SQL-Script:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dotnet ef migrations script -i -o ../../sql/update_to_latest.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The generated SQL-Script contains the IF-Statements to check which migrations needs to be applied and which are already. It also takes care of updating the migration-history-table.&lt;/p&gt;
&lt;p&gt;My build-job copies the &lt;code&gt;sql/update_to_latest.sql&lt;/code&gt;script into the build artifact.&lt;/p&gt;
&lt;p&gt;For my release-jobs I’ve created a &lt;em&gt;Task Group&lt;/em&gt; called “Migate DB to latest”. I used the task group so I can re-use this step on all my environments (actually &lt;em&gt;stage&lt;/em&gt; and &lt;em&gt;prod&lt;/em&gt;). The Task Group contains one step of type &lt;em&gt;Azure SQL Database deployment&lt;/em&gt; and executes the above SQL-Script.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2019/07/screenshot-2019-07-08-at-22.35.04.png&quot; alt=&quot;Screenshot 2019-07-08 at 22.35.04.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;Finally I’ve added this Task-Group to each environments release-steps.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2019/07/screenshot-2019-07-08-at-22.41.37.png&quot; alt=&quot;Screenshot 2019-07-08 at 22.41.37.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; To get the connection to your SQL-Server working you have to add the connection in &lt;em&gt;Azure Service Connections&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;You can find my real-world docs over at &lt;a href=&quot;https://github.com/mduu/tauchbolde/blob/develop/docs/database.md&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title>Update Azure Pipeline BuildNumber using PowerShell</title><link>https://marcduerst.com/blog/update-azure-pipeline-buildnumber-using-powershell/</link><guid isPermaLink="true">https://marcduerst.com/blog/update-azure-pipeline-buildnumber-using-powershell/</guid><description>I recently moved a build-job for our front-end library over to Azure Pipelines. This build-job builds multiple TypeScript projects where each one produces it...</description><pubDate>Mon, 21 Jan 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently moved a build-job for our front-end library over to &lt;a href=&quot;https://azure.microsoft.com/en-us/services/devops/&quot;&gt;Azure Pipelines&lt;/a&gt;. This build-job builds multiple TypeScript projects where each one produces its own NPM package using the &lt;a href=&quot;https://lernajs.io&quot;&gt;Lerna&lt;/a&gt; mono-repo toolkit.&lt;/p&gt;
&lt;p&gt;We manage the version of the packages using the &lt;a href=&quot;https://github.com/lerna/lerna/tree/master/commands/version#readme&quot;&gt;Lerna CLI&lt;/a&gt;. Lerna updates all the projects package.json as well as a file called &lt;code&gt;lerna.json&lt;/code&gt; in the root of the repo.&lt;/p&gt;
&lt;p&gt;The goal for our release build-job was to update the &lt;code&gt;BuildNumber&lt;/code&gt; of the job instance from within the running build-job to the version configured in &lt;code&gt;lerna.json&lt;/code&gt; and suffix it with the original build-number (which is a increasing integer number). The build-job should be listed as &lt;code&gt;1.4.3.598&lt;/code&gt; instead of &lt;code&gt;#598&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;/h2&gt;
&lt;p&gt;I created a little PowerShell script which I checked into the repo and added it as one of the first build steps to the build-job.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$lernaPath = &quot;$Env:BUILD_SOURCESDIRECTORY\lerna.json&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$json = Get-Content &quot;$lernaPath&quot; | Out-String | ConvertFrom-Json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$version = $json.version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$buildNumber = $Env:BUILD_BUILDNUMBER;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Write-Host &quot;##vso[build.updatebuildnumber]$version.$buildNumber&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first line gets the path of the &lt;code&gt;lerna.json&lt;/code&gt;. The second line reads the file content and converts its JSON content into a PowerShell object. The fourth line gets the version number out of that object. The fifth line gets the original build-number from Azure Pipelines using the environment variable.&lt;/p&gt;
&lt;p&gt;The most important line ist the last one. It writes a special text to the console which gets interpreted by Azure Pipelines. The &lt;code&gt;##vso[...&lt;/code&gt; is the trigger for Azure Pipelines. The function &lt;code&gt;build.updatebuildnumber&lt;/code&gt; is the Azure Pipeline function that should be called. Finally the &lt;code&gt;$version&lt;/code&gt; is the variable assigned in line three and &lt;code&gt;$buildNumber&lt;/code&gt; the variable from line four. The both variables get concat with a &lt;code&gt;.&lt;/code&gt;.&lt;/p&gt;</content:encoded></item><item><title>Fix sign-out with ASP.NET Identity Core 2.1</title><link>https://marcduerst.com/blog/fix-sign-out-with-asp-net-indentiy-core-2-1/</link><guid isPermaLink="true">https://marcduerst.com/blog/fix-sign-out-with-asp-net-indentiy-core-2-1/</guid><description>For a new app I’m writing using ASP.Net MVC Core 2.1, EF Core 2.1 and ASP.Net Identity 2.1 I had to implement the sign-out / log-out functionality. You may a...</description><pubDate>Fri, 16 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For a new app I’m writing using &lt;em&gt;ASP.Net MVC Core 2.1&lt;/em&gt;, &lt;em&gt;EF Core 2.1&lt;/em&gt; and &lt;em&gt;ASP.Net Identity 2.1&lt;/em&gt; I had to implement the sign-out / log-out functionality. You may ask why, because this is shipped with ASP.Net Core OOTB? Yes – it is. But in the default template with &lt;em&gt;ASP.Net Identity Core EF 2.1&lt;/em&gt; it does not work.&lt;/p&gt;
&lt;p&gt;I think I can work but depends on the kind auf authentication you activate. I use token authentication via cookies. The logoff action shipped with ASP.Net Core 2.1 doesn’t work for this. It forward you to the log-off page telling you, that you have been logged out but actually you are still logged in.&lt;/p&gt;
&lt;p&gt;I figured that the cookie with the authentication token is still present in the the browser session – even after you called the default logout action. The token-authentication works the way the server generate an encrypted authentication token (basically a string) that is passed forth and back using a cookie. The server validates this token with each request. Normally there is no server-side token-store or so. So there is no need to actively log-out on the server-side.&lt;/p&gt;
&lt;p&gt;To fix it I implemented my own action which removes this cookie and then redirect to the start-page of my app. To do this more reliable I gave the authentication cookie my own custom name.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;ConfigureServices()&lt;/code&gt; in &lt;code&gt;Startup.cs&lt;/code&gt; I placed the following code to configure authentication:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;services.ConfigureApplicationCookie(options =&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // Cookie settings&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    options.Cookie.HttpOnly = true;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    options.ExpireTimeSpan = TimeSpan.FromMinutes(30);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    options.LoginPath = &quot;/Identity/Account/Login&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    options.AccessDeniedPath = &quot;/Identity/Account/AccessDenied&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    options.SlidingExpiration = true;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    options.Cookie.Name = GlobalConstants.AuthCookieName;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check the custom name (stored in a global constant) for &lt;code&gt;options.Cookie.Name&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then I wrote my little logout action like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[Authorize]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[HttpGet]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;public IActionResult Logout()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    Response.Cookies.Delete(GlobalConstants.AuthCookieName);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return RedirectToAction(&quot;Index&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally I placed a link to this new &lt;code&gt;Logout&lt;/code&gt; action in my user-menu.&lt;/p&gt;
&lt;p&gt;That’s it. Hope it helps.&lt;/p&gt;</content:encoded></item><item><title>No Estimates</title><link>https://marcduerst.com/blog/no-estimates/</link><guid isPermaLink="true">https://marcduerst.com/blog/no-estimates/</guid><description>I was at a meet-up from the Software Craftsmanship Zürich on the topic of “No estimates QA session” with Vasco Duarte. I read a few things about “No estimate...</description><pubDate>Thu, 23 Aug 2018 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: img_2933.jpg --&gt;
&lt;!-- MISSING IMAGE: img_2935.jpg --&gt;
&lt;!-- MISSING IMAGE: img_2936.jpg --&gt;
&lt;!-- MISSING IMAGE: img_2937-e1535047817874.jpg --&gt;
&lt;!-- MISSING IMAGE: img_2938.jpg --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 5 images that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I was at a meet-up from the &lt;a href=&quot;https://www.meetup.com/de-DE/Software-Craftsmanship-Zurich&quot;&gt;&lt;em&gt;Software Craftsmanship Zürich&lt;/em&gt;&lt;/a&gt; on the topic of “No estimates QA session” with Vasco Duarte. I read a few things about “No estimates” (aka “NE”) before on Twitter. I got questions on how this &lt;em&gt;should&lt;/em&gt; or even &lt;em&gt;can&lt;/em&gt; work in real-life. This article is a summary of some of the things I took away from that meet-up.&lt;/p&gt;
&lt;h2 id=&quot;estimates-dont-work-in-large-scale&quot;&gt;Estimates don’t work in large scale&lt;/h2&gt;
&lt;p&gt;The main reason for the whole &lt;a href=&quot;https://twitter.com/search?q=%23noestimates&quot;&gt;#noestimates&lt;/a&gt; idea is the fact that in practice estimates do not work. If a team matches a deadline it’s normally not because of the precise estimates they did but because of smart human being. We as humans will cut corners and try to improvise so we can make the deadline.&lt;/p&gt;
&lt;p&gt;Vasco showed an experiment that a team at Microsoft did. They set up a new project to develop some peace of software. The timeframe for this was about 10 months or so. They did the hard work and estimated the entire backlog using story-points just as we know from agile/scrum practices using values from &lt;a href=&quot;https://en.wikipedia.org/wiki/Fibonacci_number&quot;&gt;Fibonacci&lt;/a&gt;  (1, 2, 3, 5, 8, …). Then they did the same only using the values 1, 2 and 3. So scaling was different. Finally they set all stories to the same story-point value. The result was that all the forecasts showed a possible release-date within the same two or three weeks over the whole period of ten months.&lt;/p&gt;
&lt;p&gt;The project-leader then came to the conclusion that they don’t need estimates. They are useless and the team can spend the time for more useful things instead like refining and slicing user-stories. Instead of estimating each user-story they now just count the user-stories and they know about how many user-stories they can do per sprint/iteration. This is done way easier and faster then estimating each story.&lt;/p&gt;
&lt;h2 id=&quot;estimates-vs-forecasts&quot;&gt;Estimates vs. forecasts&lt;/h2&gt;
&lt;p&gt;No estimates doesn’t mean you don’t have forecasts nor burn-down charts. You can do this based on the count of stories instead of story-point values. This further means that you don’t try to predict the future by guess-working but instead by measuring your work and doing a forecast based on that measured data (= number of user-stories).&lt;/p&gt;
&lt;h2 id=&quot;size-of-a-story-and-slicing&quot;&gt;Size of a story and slicing&lt;/h2&gt;
&lt;p&gt;Humans are very bad in estimating big tasks but we are better in doing so for smaller tasks.&lt;/p&gt;
&lt;p&gt;In agile but also in no-estimates user-stories should be small  very small. Not more then maybe two days. Even better not more then one day or maybe only a few hours. Ask yourself “&lt;em&gt;Will I have this done by tomorrow?&lt;/em&gt;“. If the answer is “&lt;em&gt;No&lt;/em&gt;” then you need to slice this story once more and make two out of it. If they still are too big – slice them again – and again.&lt;/p&gt;
&lt;p&gt;Slicing stories and making each story smaller and smaller does not only lead to a precise “estimate” but also further clarifies the story. This means we reduce the over-all risk because when we slice it we also clarify the smaller peaces until we can easily handle them in our brain.&lt;/p&gt;
&lt;p&gt;Another benefit of slicing is that you’ll get a 50% / 50% option to not implement a slice at all. This is very useful for managing the scope.&lt;/p&gt;
&lt;h2 id=&quot;managing-the-scope&quot;&gt;Managing the scope&lt;/h2&gt;
&lt;p&gt;Regarding to Vasco, managing the scope is the only way to fulfil deadlines successfully. Good project-leader/product-owners manage the scope from day 1. Having more but smaller user stories means that you as a PL / PO immediately have more options to manage scope for example by dropping one or another story.&lt;/p&gt;
&lt;p&gt;From Ron Jeffrey’s I got the hint to do the stories with the most business value first (if possible). Together with a good DevOps pipeline and fast iterations you’ll push releases to customers very fast and hopefully get feedback fast too. As you go through your user-stories based on busines-values this ensures the right overall direction early in the project. You then can let the customer decide which release he/she likes to take to production. It’s also up to the customer if he wants to spend money for more iterations/sprints to get even more user-stories done. I know – this doesn’t work for each project setup. For example Gov projects don’t work like this even if they say they are &lt;em&gt;agile&lt;/em&gt; they are not, never ever.&lt;/p&gt;
&lt;h2 id=&quot;offering-fixed-price-projects&quot;&gt;Offering fixed price projects&lt;/h2&gt;
&lt;p&gt;Let’s say you’re in the project business and have to offer fix priced projects on a regular basis. Projects of the size of about $200-500k need multiple days of work for estimation. Not counting the work to document them. It also needs the best employees to do it as it is really tricky and require a lot experience. Last but not least you will win only one out of a few projects. This means that this work mostly is done for free. A total waste of time in many cases but you must do offers to get work at some point.&lt;/p&gt;
&lt;p&gt;How to do this more efficiently and with no estimates?&lt;/p&gt;
&lt;p&gt;If you have to do a offer just compare the new project to your previous projects using this project catalog. This way you can tell the customer a rough price-tag very quickly. Propose to clarify further details in one (or more) workshops – which, by the way, are then paid.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;</content:encoded></item><item><title>Polyfill vendors and app bundle using Webpack 4</title><link>https://marcduerst.com/blog/polyfill-vendors-and-app-bundle-using-webpack-4/</link><guid isPermaLink="true">https://marcduerst.com/blog/polyfill-vendors-and-app-bundle-using-webpack-4/</guid><description>My goal was to have a polyfill.js bundle generated by Webpack 4 that gets inserted into the apps index.html file before any other Javascript as it must load ...</description><pubDate>Thu, 09 Aug 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My goal was to have a polyfill.js bundle generated by Webpack 4 that gets inserted into the apps &lt;code&gt;index.html&lt;/code&gt; file before any other Javascript as it must load and install the Poly- or Ponyfills before even vendor code runs.&lt;/p&gt;
&lt;p&gt;This means I basically like to have the following budles loaded:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;polyfills.js&lt;/li&gt;
&lt;li&gt;vendors.js&lt;/li&gt;
&lt;li&gt;app.js&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I struggled with this and it took me quite some time to figure it out so I give it write.&lt;/p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;/h2&gt;
&lt;p&gt;First of all I added a file which does two things: a) reference the polyfill libraries I need to b) initialise them as needed. In my case I needed &lt;a href=&quot;https://www.npmjs.com/package/es6-symbol&quot;&gt;es6-symbol&lt;/a&gt; (for &lt;a href=&quot;https://github.com/inversify/InversifyJS&quot;&gt;InversifyJS&lt;/a&gt;), &lt;a href=&quot;https://www.npmjs.com/package/es6-promise&quot;&gt;es-promise&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.com/package/whatwg-fetch&quot;&gt;whatwg-fetch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;src/polyfill.js:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/* Load polyfill:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;* This file and its dependencies get bundled into the &quot;polyfills&quot; chunk by WebPack and loaded as first scripts.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;* Add loading code of further polyfills in here as needed. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; es6_symbol&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;es6-symbol/implement&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;debug&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(es6_symbol);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; es6_promise&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;es6-promise/auto&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;debug&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(es6_promise);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;whatwg-fetch&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I then used this file as a second entry point besides my apps main file for Webpack 4:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;entry: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       polyfills: &apos;./src/polyfills.js&apos;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       app: &apos;./src/index.tsx&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I had to configure the output to use the junkname parts for the generated Javascript bundle files:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;output: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       filename: &apos;[name].bundle.js&apos;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       chunkFilename: &apos;[name].bundle.js&apos;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       path: path.resolve(__dirname, &apos;dist&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With Webpacks 4 ‘s new &lt;code&gt;optimization&lt;/code&gt; block I split all libraries from &lt;code&gt;node_modules&lt;/code&gt; into a chunk/bundle called &lt;code&gt;vendors&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;optimization: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        splitChunks: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;           cacheGroups: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              commons: {test: /[\\/]node_modules[\\/]/, name: &quot;vendors&quot;, chunks: &quot;all&quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way I get &lt;code&gt;polyfills.bundle.js&lt;/code&gt;, &lt;code&gt;vendors.bundle.js&lt;/code&gt; and &lt;code&gt;app.bundle.js&lt;/code&gt;. Then I use the &lt;em&gt;HtmlWebpackPlugin&lt;/em&gt; to patch the scripts HTML tags into the &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The problem with this is that the scripts-tags are generated in the wrong order so &lt;code&gt;polyfills.bundle.js&lt;/code&gt; will not be loaded as the first package which results in errors. To address this I had to do quite a while of research so I figured one can change the chunk sort mode to &lt;code&gt;manual&lt;/code&gt; and specify the chunks in the &lt;code&gt;chunks&lt;/code&gt; field as a string array.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;chunksSortMode: &quot;manual&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;chunks: [&apos;polyfills&apos;, &apos;vendors&apos;, &apos;app&apos;],&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I could not find any official documentation about this option but finally got hints in the GitHub issues that this option exists and one hint how to use them.&lt;/p&gt;
&lt;p&gt;Here is my the more complete &lt;code&gt;webpack.config.js&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;webpack.config.js:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; path&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; webpack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;webpack&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ExtractTextPlugin&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;extract-text-webpack-plugin&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; HtmlWebpackPlugin&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;html-webpack-plugin&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; CopyWebpackPlugin&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;copy-webpack-plugin&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    entry: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       polyfills: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;./src/polyfills.js&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       app: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;./src/index.tsx&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    output: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       filename: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;[name].bundle.js&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       chunkFilename: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;[name].bundle.js&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       path: path.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(__dirname, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;dist&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    devtool: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;source-map&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    resolve: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       extensions: [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;.ts&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;.tsx&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;.jsx&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;.json&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    module: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       rules: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;          ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    plugins: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;       ...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;       new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; HtmlWebpackPlugin&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          template: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;src/index.html&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          filename: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;index.html&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          chunksSortMode: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;manual&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          chunks: [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;polyfills&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;vendors&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;app&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    optimization: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        splitChunks: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;           cacheGroups: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              commons: {test:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#85E89D;font-weight:bold&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;/]&lt;/span&gt;&lt;span style=&quot;color:#DBEDFF&quot;&gt;node_modules&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#85E89D;font-weight:bold&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;/]&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, name: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;vendors&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, chunks: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;all&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;       }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded></item><item><title>State handling in React apps</title><link>https://marcduerst.com/blog/state-handling-in-react-apps/</link><guid isPermaLink="true">https://marcduerst.com/blog/state-handling-in-react-apps/</guid><description>We use React for most of our current web-frontends. For older React Apps we used the MobX (databinding-library for MVVM) and then moved over to Redux. But ev...</description><pubDate>Sat, 04 Aug 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;
&lt;p&gt;We use React for most of our current web-frontends. For older React Apps we used the MobX (databinding-library for &lt;a href=&quot;https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel&quot;&gt;MVVM&lt;/a&gt;) and then moved over to Redux. But even with Redux we where not quite happy because we used Redux for nearly every button enable/disable state. We are also committed to TypeScript and its strong typings even for our actions and action-creators.&lt;/p&gt;
&lt;p&gt;To get an impression what kind of code we wrote see &lt;a href=&quot;https://github.com/Microsoft/TypeScript-React-Starter#typescript-react-starter&quot;&gt;this TypeScript Tutorial&lt;/a&gt; and &lt;a href=&quot;https://marcduerst.com/blog/structuring-ab-app-with-react-redux-and-typescript&quot;&gt;this blog-post.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-problems&quot;&gt;The problems&lt;/h2&gt;
&lt;p&gt;With this one ends up with a huge global state-tree maintained by a lot of reducers. Even small apps quickly had 20+ reducers. Each reducer serves multiple actions which needed their action definitions and their action-creators as you see in the TypeScript tutorial.&lt;/p&gt;
&lt;p&gt;The main problem was not the amount of code but the maintainability and the readability of all this code. When one changed the user-interface one had to change the state-tree and all the actions and action-creators involved. If the UI-workflow changed more fundamentally, also the whole action and state-tree had to be re-thought, decoupled and refactored or re-built. This even in smaller apps (but with non-trivial UI) became a big issue sooner then later.&lt;/p&gt;
&lt;p&gt;Another issue: for UI interaction we had to think in the &lt;a href=&quot;https://martinfowler.com/eaaDev/EventSourcing.html&quot;&gt;event-sourcing pattern&lt;/a&gt; instead of a classic view-model (MVVM). Event-Sourcing is a good pattern but not really natural for UI-stuff like “when is which button enabled” or “what parts of the component are shown/hidden”. For this stuff its way over the top. Again, think of if EVERYTHING goes though action-creators, actions, reducers and finally into the state which then gets mapped to the React component properties.&lt;/p&gt;
&lt;p&gt;We realised (thanks, chief) that we where way to slow implementing user-interfaces comparing to other stacks we used in the past.&lt;/p&gt;
&lt;h2 id=&quot;our-solution&quot;&gt;Our solution&lt;/h2&gt;
&lt;p&gt;Four of us took on this topic and sat together, evaluated different things (even MobX again) and we then came up with the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Use Redux for global state – stuff that is used in different parts of the application.&lt;/strong&gt;&lt;br&gt;
Eg. central master-data fetched from the server, login-information, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use React component state for local state only.&lt;/strong&gt;&lt;br&gt;
Eg. if a component must maintain a enabled-disabled button-state this can be done easily in the local React component-state (the setState()-thing and must not go though all the Redux code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use the new React Context for related component state.&lt;/strong&gt;&lt;br&gt;
Eg. if a set of components are used to build a edit-form introduce a context on the top level component of the form and consume this within the sub-components like the soft-keyboard, advanced input-controls like editors, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Its up to the developer to decide when to use Redux and when React Contexts. Its not a hard line. Think of Redux-State as the central singleton-store where the React Context is scoped state that gets dropped afterwards. Further more the context can be hierarchically cascaded. So if your state’s nature is more hierarchically and temporary you probably want to use the React Context instead of Redux. Same applies if you like to build a view-model with data and UI-logic in one place you’ll go with React Context. On the other hand, if things need to be persisted or you like to use history (eg. the Redux dev-tools) you will choose Redux.&lt;/p&gt;
&lt;h2 id=&quot;the-result&quot;&gt;The result&lt;/h2&gt;
&lt;p&gt;We practiced this at a few placed and quickly felt way more productive and used way less lines of code for the same UI. The result was especially mind-blowing when we changed a set of components that build up a complex value editor (used for touch-only devices used in a &lt;a href=&quot;https://en.wikipedia.org/wiki/Progressive_Web_Apps&quot;&gt;PWA&lt;/a&gt;) to use the React Contexts instead of Redux. We could remove a ton of code and the code get way more readable. Implementing new features to this value-editor became a relatively easy task. Using Redux the new editor-features require us to rebuild large parts of the state-handling code (and its tests) because actions, reducers and state is decoupled.&lt;/p&gt;
&lt;p&gt;With the above three recommendations we quickly felt to be more productive in building and maintaining the UI while not loosing testability of our UI logic.&lt;/p&gt;
&lt;h3 id=&quot;a-few-words-about-redux&quot;&gt;A few words about Redux&lt;/h3&gt;
&lt;p&gt;Don’t get me wrong. This is not a post against the use of Redux. We still like Redux and its Dev-Tools a lot. A really nice and transparent thing that makes debugging relatively easy. We don’t drop Redux entirely. We just don’t use it for everything anymore and therefore reducing its usage to a reasonable usage.&lt;/p&gt;
&lt;p&gt;So, use Redux wisely, young Padawan 🙂&lt;/p&gt;</content:encoded></item><item><title>Structuring an app with React, Redux and TypeScript</title><link>https://marcduerst.com/blog/structuring-ab-app-with-react-redux-and-typescript/</link><guid isPermaLink="true">https://marcduerst.com/blog/structuring-ab-app-with-react-redux-and-typescript/</guid><description>I’m relatively new to the stack of React, Redux and TypeScript but I had to do a lot of coding in this area over the past months. To get started I read some ...</description><pubDate>Tue, 17 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m relatively new to the stack of React, Redux and TypeScript but I had to do a lot of coding in this area over the past months. To get started I read some books (&lt;em&gt;yea&lt;/em&gt; old school – baby), got some nice and helpful intro by my co-workers and read a ton of online articles and tutorials.&lt;/p&gt;
&lt;p&gt;But somehow it didn’t feel structured enough for me. So I revisited my code and where I’ve put things multiple times and slightly modified it on each attempt. With the current state I am quite happy bit its far from being perfect. So here is how I structure things as of today. No guarantee that I will be the same structure next week but hey, this is how the weg works 😉&lt;/p&gt;
&lt;h2 id=&quot;readings&quot;&gt;Readings&lt;/h2&gt;
&lt;p&gt;First of all a few good reading everyone should read first.&lt;/p&gt;
&lt;p&gt;A good reading for React/Redux apps is the &lt;a href=&quot;https://redux.js.org&quot;&gt;Redux documentation&lt;/a&gt;. Several pages have very good information on how to structure things – even if they are not focused on TypeScript and type-safety. Each time a read – or better: re-read – chapters of this documentation I have a &lt;em&gt;aha&lt;/em&gt; moment and think by myself “oh god, I’ll never get this all together in my code (a positive thing for the Redux docs).&lt;/p&gt;
&lt;p&gt;Another good reading related to TypeScript is the &lt;a href=&quot;https://github.com/Microsoft/TypeScript-React-Starter#typescript-react-starter&quot;&gt;TypeScript React Starter tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-result&quot;&gt;The result&lt;/h2&gt;
&lt;p&gt;Let’s start straight with the result. Here is how my files and folder structure currently looks like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+ src&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  + components&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    + MyAppInputBox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - MyAppInputBox.tsx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - MyAppInputBox.less&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    + MyAppPageLayout&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - MyAppPageLayout.tsx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - MyAppPageLayout.less&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    + ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  + core&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    + entities&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - IContract.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    + api&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - ApiManager.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - MyAppServer.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - Fetcher.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - IResponseObject.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    + ioc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - ServiceRegistry.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - ServiceIdentifiers.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  + redux&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    + globals&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      + actions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        - factories.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        - index.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        - types.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      + logic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        - serverInfo.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        - ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      + reducers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        - globalsReducer.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        - ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        - index.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      index.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      state.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    + reducers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - index.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - rootReducer.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - pagesReducer.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    index.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    state.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  + pages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    + StartPage&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      + components&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      + redux&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      + scences&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - StartPage.tsx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      - StartPage.less&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    + ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;index.ts&lt;/code&gt; files re-export the relevant members per folder. One can think of them as a kind of “published” visibility or the “public API of that folder”. They also allow for shorter &lt;code&gt;import&lt;/code&gt; statements.&lt;/p&gt;
&lt;h2 id=&quot;components&quot;&gt;Components&lt;/h2&gt;
&lt;p&gt;There are many ways one can structure its React components and tons tutorials and articles can be found online. I like to divide my components in different categories depending on their role.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Simple components that are not connected to the global state and just do some rendering. They are located within &lt;em&gt;pages&lt;/em&gt; or other “components* and are stored within a `components&lt;code&gt;folder. Other sources I found online call them&lt;/code&gt;elements“ but IDE’s – like &lt;em&gt;WebStorm&lt;/em&gt; – have smart defaults for folder called &lt;em&gt;components&lt;/em&gt;. That’s why I stick with this name.&lt;/li&gt;
&lt;li&gt;Components that compose several simple components to a more complex layout and may are connected to the global state. The are &lt;em&gt;pages&lt;/em&gt; or located in &lt;em&gt;scenes&lt;/em&gt; subfolders. You’ll find other names for these components online like &lt;em&gt;Views&lt;/em&gt; (a totally overused word in IT in my point of view), container-components, etc. I’ve started putting them into local &lt;code&gt;scenes&lt;/code&gt; folders instead of local &lt;code&gt;components&lt;/code&gt; folders.&lt;/li&gt;
&lt;li&gt;Root level components that act as &lt;em&gt;Pages&lt;/em&gt; or sometimes called &lt;em&gt;Scenes&lt;/em&gt;. I find it handy to treat the entry point components for each new page (top-level component that renders the entire screen) separately. Located in &lt;code&gt;src/pages&lt;/code&gt; or &lt;code&gt;src/scenes&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Central components like input controls, logo’s, page-template etc. that are re-used all over in the application. I put these components in &lt;code&gt;src/components&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This whole chapter is not yet in its final stage. Chances are quite good that I will further change the structuring of the React components in the future. But as I wrote – there are so many systems/concepts online for structuring React components.&lt;/p&gt;
&lt;h2 id=&quot;redux&quot;&gt;Redux&lt;/h2&gt;
&lt;p&gt;Let’s talk about all the Redux related code and where I put those things.&lt;/p&gt;
&lt;p&gt;First of all I normally have a &lt;code&gt;src/redux&lt;/code&gt; where I put in my global Redux-related code which is not specific to a &lt;em&gt;Page&lt;/em&gt; or &lt;em&gt;Component&lt;/em&gt;. Things like my root state and reducers as well as setting up the Redux store itself goes in here.&lt;/p&gt;
&lt;p&gt;More local sub-state – eg. the one specific to a certain page – goes into their own &lt;code&gt;./redux&lt;/code&gt; folder within the scope they belong to (Page, Component, etc.).&lt;/p&gt;
&lt;p&gt;The Redux folders are always structured the same way:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+ actions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(+ logic)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+ reducers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- index.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- state.ts&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;state&quot;&gt;State&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;state.ts&lt;/code&gt; contains two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The interfaces describing the states and sub-states.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;getXyState(appState: IAppState): IXyState&lt;/code&gt; per state interface to get the given sub-state object out of the store. Using these functions the components etc. don’t need to know the structure of my reducers but only that fields are in the given state. So the only places where the cascading of my state-nodes matter are the &lt;code&gt;combineReducers()&lt;/code&gt; and these getter functions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A note on typing the states: I always use interfaces to describe / type the surface of a state. Others may use type aliases instead interfaces. I prefer interfaces.&lt;/p&gt;
&lt;h3 id=&quot;actions&quot;&gt;Actions&lt;/h3&gt;
&lt;p&gt;Note: Actions are per state – not per reducer. The actions therefore are for all reducers within the given state node.&lt;/p&gt;
&lt;p&gt;When using TypeScript the actions get more code then with vanilla Javascript because we like to type them and not using string literals all over. Then we need the factory functions (aka action creators) which produce the action objects. If one puts this all into one file per state this file quickly gets large. That’s why I split this code and introduced the &lt;code&gt;actions&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;./redux/actions/&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;factories.ts&lt;/code&gt;: Contains all the functions that create the action objects (aka action creators). For example:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; fetchContractsError&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;errorMessage&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; FetchContractsError&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    type: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;FETCH_STARTABLE_CONTRACTS_ERROR&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    errorMessage&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;types.ts&lt;/code&gt;: Contains all the action type definition like shown on the TypeScript quick-starter tutorial and this is the only place where we use the string literals for action names:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; FETCH_CONTRACTS_ERROR&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;FETCH_CONTRACTS_ERROR&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; FETCH_CONTRACTS_ERROR&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; typeof&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; FETCH_CONTRACTS_ERROR&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; FetchContractsError&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;  type&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; FETCH_CONTRACTS_ERROR&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;  errorMessage&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ìndex.ts&lt;/code&gt;: Pulls the above things together by re-exporting them.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export * from &apos;./types&apos;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export * from &apos;./factories&apos;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ve written Live-Templates for WebStorm for them so most of this code generated automatically. I just have to enter the new action name and fill it with additional fields.&lt;/p&gt;
&lt;p&gt;I am thinking to change the content of the actions folder in the future the way that I have one file per action which contains the action-object typings and the factory-function (action creator). This way if I later need to move a action into another state-node I can grab the entire file and let &lt;em&gt;WebStorm&lt;/em&gt; fix all the imports. But this would lead in even more files. As I said: thinking about it.&lt;/p&gt;
&lt;h3 id=&quot;reducers&quot;&gt;Reducers&lt;/h3&gt;
&lt;p&gt;The Reducers are stored within the &lt;code&gt;reducers&lt;/code&gt; folders and are structured as shown in Redux docs and the TypeScript tutorial. Nothing special here except that we started putting the reducers into classes so we can use constructor-injection from the IoC container (we use &lt;em&gt;Inversify&lt;/em&gt; and are happy with it). To get these reducers into Redux we write a wrapper-function per reducer which instantiates these classes using the IoC container (using the service-locator (anti-)pattern at this point) and can be used with the &lt;code&gt;combineReducer()&lt;/code&gt; function of Redux.&lt;/p&gt;
&lt;p&gt;Why do we need dependency injection (DI) in Reducers? We heavily rely on unit-testing (using Jest and WallabyJs). To do so we split our code using the SOLID principals into small classes that separate concerns. For example we extract domain-/business-logic into their own service-classes which we then register with the IoC container. To get instances of them we rely on constructor-injection and thats why we need classes and instantiate them using the service-locator pattern.&lt;/p&gt;
&lt;h3 id=&quot;logic-folders&quot;&gt;Logic folders&lt;/h3&gt;
&lt;p&gt;Not sure if this name will stay for long but it mainly contains stuff that don’t belong to the actions and not to reducers. For example async-actions (aka meta-actions) are stored here as they are not plain actions and also contain a decent amount of logic (eg. how to fetch server-data incl. error-handling). Logic utilities or sometimes the domain-/business-services goes in here as well. Its content is not highly standardized yet.&lt;/p&gt;
&lt;h2 id=&quot;core&quot;&gt;Core&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;src/core&lt;/code&gt; folder contains client-side code that does not belong to either a specific React component nor a specific Redux state. Stuff like the fetch-client or domain-entities definition (= TypeScript interfaces) go in here. The whole IoC configuration is stored in here too as well as domain services and some other central code.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;With this structure I feel kind of in control. But on the other hand we have a lot of files and folders and I always find things I don’t like. For example see the note on (re-)structuring the &lt;code&gt;actions&lt;/code&gt; folder. This is why I declare this structure as &lt;em&gt;work in progress&lt;/em&gt;. I wrote it down so you guys can give feedback and I can start over improving it – again 🙂&lt;/p&gt;</content:encoded></item><item><title>JavaScript async/await in React components</title><link>https://marcduerst.com/blog/javascript-async-await-in-react-components/</link><guid isPermaLink="true">https://marcduerst.com/blog/javascript-async-await-in-react-components/</guid><description>Again some notes from my recent React and Javascript/TypeScript learnings. I knew already how to use Promises by building method chains with .then() or .catc...</description><pubDate>Tue, 20 Mar 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Again some notes from my recent React and Javascript/TypeScript learnings. I knew already how to use Promises by building method chains with &lt;code&gt;.then()&lt;/code&gt; or &lt;code&gt;.catch()&lt;/code&gt; to chain the asynchronous actions together. But as I am a fan of C#’s &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; and read that JS/TS does support them too, I liked to figure how to use them in my React apps so the code will get even cleaner as with the method chains.&lt;/p&gt;
&lt;h1 id=&quot;scenario&quot;&gt;Scenario&lt;/h1&gt;
&lt;p&gt;When my React UI need data they have to request them from a REST-Server (API). Best practice here is to do this work asynchronous so the UI-Thread stays responsive.&lt;/p&gt;
&lt;p&gt;When speaking of React UI I mean a React.Component using its standard methods that like &lt;code&gt;componentDidMount()&lt;/code&gt;. This method is where one should load the server-data with regards to the &lt;a href=&quot;https://reactjs.org/docs/react-component.html#componentdidmount&quot;&gt;React doc’s&lt;/a&gt;. This method is normally not marked &lt;code&gt;async&lt;/code&gt; and therefore one can not use &lt;code&gt;await&lt;/code&gt;. I guess this is why many React developers don’t use &lt;code&gt;await&lt;/code&gt; but method chains.&lt;/p&gt;
&lt;h1 id=&quot;solution&quot;&gt;Solution&lt;/h1&gt;
&lt;p&gt;How can I utilise &lt;code&gt;await&lt;/code&gt; to simplify my asynchronous code in React apps?&lt;/p&gt;
&lt;p&gt;First I implemented an async service-method which will be responsible to fetch data from the server (for example by using the &lt;code&gt;fetch()&lt;/code&gt; API which is based on Promises).&lt;/p&gt;
&lt;p&gt;The following code is my in-memory test-service which returns fixed values instead calling a real server. Hint: I used the &lt;code&gt;Promise.resolve()&lt;/code&gt; function to return the fixed value right away.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;async getEntities(): Promise {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return Promise.resolve(entities);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the &lt;code&gt;async&lt;/code&gt; keyword here and that I return a Promise. Side-note for C# developers: Javascript &lt;code&gt;Promise&lt;/code&gt; is exactly that &lt;code&gt;Task&lt;/code&gt;is in C#.&lt;/p&gt;
&lt;p&gt;Then I’ve changed my React Component’s &lt;code&gt;componentDidMount()&lt;/code&gt; mount method to an async method by also using the &lt;code&gt;async&lt;/code&gt; keyword:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ContactList&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; React&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; componentDidMount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; entities&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; apiManager&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().contactService.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getEntities&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ entities });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Please not that this way I can use &lt;code&gt;await&lt;/code&gt; to await the result of my async function &lt;code&gt;getEntities()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;React seems to call this &lt;code&gt;componentDidMount()&lt;/code&gt; even if it is async now.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Cool – eyy?&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title>Compile-check Less CSS classnames using TypeScript and Webpack</title><link>https://marcduerst.com/blog/compile-check-less-css-classnames-using-typescript-and-webpack/</link><guid isPermaLink="true">https://marcduerst.com/blog/compile-check-less-css-classnames-using-typescript-and-webpack/</guid><description>As I am making myself familiar with modern frontend development based on React, TypeScript, Webpack and some more I learned something really cool. I like to ...</description><pubDate>Thu, 08 Mar 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As I am making myself familiar with modern frontend development based on React, TypeScript, Webpack and some more I learned something really cool. I like to write this down not only for you – dear reader – but also for my own reference.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;/h2&gt;
&lt;p&gt;Let’s say you have a trivial React component like this where you specify a &lt;code&gt;classsName&lt;/code&gt; to tell what CSS class should be used:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyComponent&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyComponentProps&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; MyComponent;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem with this is that we don’t have any compiler-check to ensure this class &lt;code&gt;myclass&lt;/code&gt; really exists in our LESS file. So if we have a Typo or later change the LESS file we can not be sure all classes/selectors are still valid. Not even the browser will show that. It silently breaks. Bad thing!&lt;/p&gt;
&lt;h2 id=&quot;a-solution&quot;&gt;A solution&lt;/h2&gt;
&lt;p&gt;Using Webpack and the LESS loader one can fix this by check this at compile time. To do so you can define the style and its classname in the LESS file and import it into .tsx files. The LESS loader for webpack will expose the following LESS variables to the build process where the TypeScript loader (used for the .tsx files) can pick it up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MyComponent.less:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@my-class: ~&apos;:local(.myClass)&apos;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@{my-class}{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;width: 100%;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;background-color: green;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the &lt;code&gt;local()&lt;/code&gt; function supported by the LESS loader (see webpack config at the end) which scopes that class to a local scope.&lt;/p&gt;
&lt;p&gt;The above LESS files can be typed and imported into the .TSX file like this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MyComponent.tsx:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; TStyles&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;myClass&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; styles&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; TStyles&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;./MyComponent.less&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyComponent&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyComponentProps&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; MyComponent;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then firing your build the .less file gets picked up using the &lt;code&gt;require()&lt;/code&gt; function and checked against the TypeScript type &lt;code&gt;TStyles&lt;/code&gt;. The property &lt;code&gt;myClass&lt;/code&gt; will contain the LESS/CSS classname as defined in the .less file.&lt;/p&gt;
&lt;p&gt;I then can use the &lt;code&gt;styles.myClass&lt;/code&gt; instead of the string literal of the original code.&lt;/p&gt;
&lt;p&gt;To get this working ensure you have to LESS loader included in your webpack configuration (you probably have if your are already using LESS:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;webpack.json:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;module: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;rules: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;test: /.tsx?$/,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;loader: &quot;ts-loader&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;test: /.less$/,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;use: ExtractTextPlugin.extract({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;use: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;loader: &quot;css-loader&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;options: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;localIdentName: &apos;[local]--[hash:5]&apos;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sourceMap: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;loader: &quot;less-loader&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;options: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sourceMap: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;fallback: &quot;style-loader&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The samples use LESS stylesheets but one can to the same with SCSS/SASS – I guess. You just have to use another loader for webpack and therefore the syntax supported by that loader.&lt;/p&gt;
&lt;p&gt;No broken CSS classnames anymore – isen’t this cool? Let me know your feedback.&lt;/p&gt;</content:encoded></item><item><title>Calculating MD5 hash over multiple strings with C#</title><link>https://marcduerst.com/blog/calculating-md5-hash-over-multiple-strings-with-c/</link><guid isPermaLink="true">https://marcduerst.com/blog/calculating-md5-hash-over-multiple-strings-with-c/</guid><description>I just spent a fair amount of hours calculating one MD5 hash code over multiple strings so I thought I write this down. Please note that the same principle c...</description><pubDate>Tue, 06 Feb 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I just spent a fair amount of hours calculating one MD5 hash code over multiple strings so I thought I write this down. Please note that the same principle can be used for SHA1 and other algorithms provided by the .Net Framework. Please note that MD5 is not the strongest crypto. If you need strong security choose another algorithm.&lt;/p&gt;
&lt;p&gt;To build one hash code for multiple data blocks one needs the &lt;code&gt;TransformBlock()&lt;/code&gt; and the &lt;code&gt;TransformFinalBlock()&lt;/code&gt; functions of .Net’s crypro API’s like the &lt;code&gt;MD5&lt;/code&gt; class.&lt;/p&gt;
&lt;p&gt;Here is my main routine which calculates one MD5 hash over a whole set of &lt;code&gt;ITranslationEntry&lt;/code&gt;. Each &lt;code&gt;ITranslationEntry&lt;/code&gt; contains some string and a list of sub-classes (&lt;code&gt;Texts&lt;/code&gt;) which strings too. I need one MD5 hash for the whole object hierarchy so I can detect changes in this structure which then needs to trigger some other logic.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; md5&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; MD5.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Create&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AddStringToHash&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ICryptoTransform&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cryptoTransform&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; textToHash&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                    var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; inputBuffer&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Encoding.UTF8.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GetBytes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(textToHash);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                    cryptoTransform.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TransformBlock&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(inputBuffer, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, inputBuffer.Length, inputBuffer, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; trans&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; defaultEntries)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;                    AddStringToHash&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(md5, trans.Category);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;                    AddStringToHash&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(md5, trans.Key);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                    foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; transText&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; trans.Texts)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;                        AddStringToHash&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(md5, transText.TwoLetterLanguageCode);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;                        AddStringToHash&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(md5, transText.Text);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                md5.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TransformFinalBlock&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; byte&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                return&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ConvertByteArrayToString&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(md5.Hash);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above code creates a instance of .Net’s &lt;code&gt;MD5&lt;/code&gt; class using its &lt;code&gt;Create()&lt;/code&gt; factory method. Make sure you dispose this instance when not needed anymore as it uses operating-system resources. That’s why I put it in a &lt;code&gt;using&lt;/code&gt; statement.&lt;/p&gt;
&lt;p&gt;Next I have a local function called &lt;code&gt;AddStringToHash()&lt;/code&gt; which does exactly what its name says by using the &lt;code&gt;TransformBlock()&lt;/code&gt; method of the &lt;code&gt;MD5&lt;/code&gt; class. This method does two things. First id calculates the hash for the given block (the string in our case) and adds it to the MD5. Then it copies the input data to output buffer. I couldn’t figure out why it does this. But specify the input buffer as the output buffer does the job here.&lt;/p&gt;
&lt;p&gt;Then we use this local function to add some of the property values when looping over our object hierarchy.&lt;/p&gt;
&lt;p&gt;Finally we must call &lt;code&gt;TransformFinalBlock()&lt;/code&gt;. Otherwise .Net will throw an exception when trying to access &lt;code&gt;MD5.Hash&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The hash itself can be retrieved as a byte-array from &lt;code&gt;MD5.Hash&lt;/code&gt;. As I need a proper string representation of it I added a little conversion method. Here’s the code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ConvertByteArrayToString&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;bytes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; sb&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; StringBuilder&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; b&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; bytes)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                sb.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Append&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(b.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ToString&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;X2&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sb.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ToString&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hope this saves you some time if try to calculate one hash code for several data chunks.&lt;/p&gt;</content:encoded></item><item><title>How to build and publish NuGet packages with source symbols to VSTS</title><link>https://marcduerst.com/blog/how-to-build-and-publish-nuget-packages-with-source-symbols-to-vsts/</link><guid isPermaLink="true">https://marcduerst.com/blog/how-to-build-and-publish-nuget-packages-with-source-symbols-to-vsts/</guid><description>We read about that Visual Studio Team Services (VSTS) now not only support hosting your Nuget package feeds but also your source-symbols and source-symbol pa...</description><pubDate>Thu, 11 Jan 2018 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: releasejob_1.png --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 1 image that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We read about that Visual Studio Team Services (VSTS) now not only support hosting your Nuget package feeds but also your source-symbols and source-symbol packages. This sounds very promissing in case you host your own Nuget’s und like to be able to debug them within your applications.&lt;/p&gt;
&lt;p&gt;At my work we have an internal framework that is packaged in multiple Nuget packages. These packages are built by the VSTS Build-Job and get published to the VSTS hosted package feed in the Release-Job. It is consumed and used by our application using VSTS as a regular Nuget-Server.&lt;/p&gt;
&lt;p&gt;As it was not trivial to get all running I do a quick summary here. Please also note, that a lot the Microsoft Docs are at least a little out of date. That seems to be the result of the new agile world we are living in.&lt;/p&gt;
&lt;h2 id=&quot;install-package-management-and-enable-source-symbol-server&quot;&gt;Install package-management and enable source-symbol server&lt;/h2&gt;
&lt;p&gt;First of all you have to install the package-manager extension in VSTS. As source-symbol server feature currently is in preview you have to enable this feature-preview in the VSTS admin section. Read more about it &lt;a href=&quot;https://docs.microsoft.com/en-us/vsts/package/install&quot;&gt;here…&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;index-sources--publish-symbols&quot;&gt;Index Sources &amp;#x26; Publish Symbols&lt;/h2&gt;
&lt;p&gt;Then you compile your assembly’s by default you’ll get a .PDB file. This default is not only for debug- but also for release-builds. You can configure it the project settings of each assembly you have. Enable PDB generation. PDB’s are binary files containing debugging information.&lt;/p&gt;
&lt;p&gt;To get enhanced mapping information pushed into the PDB’s you’ll need to add the build task “Index Source &amp;#x26; Publish Symbols”.&lt;/p&gt;
&lt;p&gt;Build-Tasks&lt;/p&gt;
&lt;p&gt;Task Configuration&lt;/p&gt;
&lt;p&gt;As you can see in the above screen-shoots I inserted this build task after building the solution and running the unit-tests. I set it to publish to the same VSTS account as the build-job runs.&lt;/p&gt;
&lt;p&gt;For packing Nuget packages one can also configure to pack symbol-packages too. That means that not one but two packages will be generated by the Nuget-Task: the regular Nuget and the .symbols-Nuget package. So’ll see the important peaces here:&lt;/p&gt;
&lt;p&gt;Build-Tasks&lt;/p&gt;
&lt;p&gt;Nuget Task Configuration&lt;/p&gt;
&lt;p&gt;That’s it for the build-job. Let’s go to deplyoment (aka Release-Job).&lt;/p&gt;
&lt;h2 id=&quot;deployment-aka-release-job&quot;&gt;Deployment (aka Release-Job)&lt;/h2&gt;
&lt;p&gt;The good news here is that you don’t have to do anything to support source-symbol packages if you use the defaults of VSTS. The symbol-Packages get automatically picket up by the Nuget-Task if they exists in your build-artifacts.&lt;/p&gt;
&lt;p&gt;Make sure you are using the newer Nuget-Task as the old one is deprecated anyway. Then make sure the .symbols.nupkg is in your path configuration. Again you can configure to publish it to your VSTS account’s package-management. I show you how it looks on my Release-job:&lt;/p&gt;
&lt;p&gt;This should allow you to build and publish your own Nuget packages to your VSTS Package-Manager. You then can configure the package-manager as an additional source-server in your VisualStudio configuration. Read &lt;a href=&quot;https://docs.microsoft.com/en-us/vsts/package/symbols/debug-with-symbols-visual-studio&quot;&gt;here&lt;/a&gt; how to do this.&lt;/p&gt;</content:encoded></item><item><title>Visual Studio for Mac with Ligatures font Fira Code</title><link>https://marcduerst.com/blog/visual-studio-for-mac-with-ligatures-font-fira-code/</link><guid isPermaLink="true">https://marcduerst.com/blog/visual-studio-for-mac-with-ligatures-font-fira-code/</guid><description>In a previous post I described how to set up the Ligatures font “Fira Code” in Visual Studio 2017. As I startet coding these days in Visual Studio for Mac (V...</description><pubDate>Thu, 11 Jan 2018 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: screen-shot-2018-01-11-at-20-50-27.png --&gt;
&lt;!-- MISSING IMAGE: screen-shot-2018-01-11-at-20-50-58.png --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 2 images that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In a &lt;a href=&quot;https://marcduerst.com/blog/visual-studio-2017-support-for-ligatures-fonts-like-fire-code&quot;&gt;previous post&lt;/a&gt; I described how to set up the Ligatures font “Fira Code” in Visual Studio 2017. As I startet coding these days in &lt;em&gt;Visual Studio for Mac&lt;/em&gt; (Version 7) I like to have Ligatures fonts in this IDE too. So I started a journey to set up “Fira Code” on my MacBook Pro with macOS &lt;em&gt;HighSierra&lt;/em&gt; installed.&lt;/p&gt;
&lt;p&gt;I had no clue how to install new fonts on a Mac. So I tried to download the TTF fonts and drop them in the folder &lt;em&gt;/Library/Fonts&lt;/em&gt; without success. On the Fira Code Github site they write about click “&lt;em&gt;Install Font&lt;/em&gt;“. This didn’t work too. Then I tried adding them via the app “&lt;em&gt;Font Book&lt;/em&gt;” (part of macOS). Didn’t work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Finally I used the method by installing it using the two “&lt;em&gt;brew&lt;/em&gt;” command as described &lt;a href=&quot;https://github.com/tonsky/FiraCode/wiki&quot;&gt;here&lt;/a&gt; as I have &lt;em&gt;brew&lt;/em&gt; already installed on my Mac anyway. This finally worked!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The rest then was easy as Visual Studio for Mac supports Ligatures fonts out of the box:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open Visual Studio for Mac&lt;/li&gt;
&lt;li&gt;Open &lt;em&gt;Preferences &gt; Fonts&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Choose Fira Core Retina as the editor font.&lt;/li&gt;
&lt;li&gt;Done.&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title>How to run xUnit tests in Visual Studio for Mac</title><link>https://marcduerst.com/blog/how-to-run-xunit-tests-in-visual-studio-for-mac/</link><guid isPermaLink="true">https://marcduerst.com/blog/how-to-run-xunit-tests-in-visual-studio-for-mac/</guid><description>In the current version of Visual Studio for Mac there is “Add file” template for xUnit Unit-Tests. Nice and easy. But how to run these tests? The problem is,...</description><pubDate>Mon, 08 Jan 2018 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: vs_mac_unittest_pad_xunit.png --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 1 image that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2018/01/vs_mac_extension_xunit.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In the current version of &lt;em&gt;Visual Studio for Mac&lt;/em&gt; there is “Add file” template for xUnit Unit-Tests. Nice and easy. But how to run these tests? The problem is, that the default installation of Visual Studio for Mac does not discover these xUnit Tests even if you do a full rebuild.&lt;/p&gt;
&lt;p&gt;After searching a while I figured that one need to install the extension called “&lt;em&gt;&lt;strong&gt;xUnit.NET 2 testing framework support&lt;/strong&gt;&lt;/em&gt;” from the Extension Gallery.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2018/01/vs_mac_extension_xunit.png&quot; alt=&quot;vs_mac_extension_xunit&quot;&gt;&lt;/p&gt;
&lt;p&gt;After that one need to restart Visual Studio for Mac and do a full rebuild. The tests will then show up in the “Unit Tests” pad.&lt;/p&gt;</content:encoded></item><item><title>Line breaks in webpages</title><link>https://marcduerst.com/blog/line-breaks-in-webpages/</link><guid isPermaLink="true">https://marcduerst.com/blog/line-breaks-in-webpages/</guid><description>I just got a bug-report where a field label is too long and (with the use of Bootstrap 3) doesn’t wrap but get cut off. So I took this opportunity to do some...</description><pubDate>Thu, 03 Aug 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2017/08/wordbreaks.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I just got a bug-report where a field label is too long and (with the use of Bootstrap 3) doesn’t wrap but get cut off. So I took this opportunity to do some research about state of line-breaking in webpages and web-apps as of 2017.&lt;/p&gt;
&lt;h2 id=&quot;css-word-wrap&quot;&gt;CSS word-wrap&lt;/h2&gt;
&lt;p&gt;Since ages there is the CSS option called “&lt;em&gt;word-wrap&lt;/em&gt;“. One can give it a value of “&lt;em&gt;break-word&lt;/em&gt;” so the browser will break the text if it doesn’t fit into its box. For my Bootstrap 3 UI I put the following CSS in place for testing:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;.form-group label.control-label {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    word-wrap: break-word;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looks like it even works in crappy Internet Explorer.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Downside:&lt;/strong&gt; The browser don’t know anything about break-points or even word-breaking rules from the language used. So they break long words anywhere.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;html-5-word-break-points&quot;&gt;HTML 5 word break-points&lt;/h2&gt;
&lt;p&gt;With HTML 5 we got a new HTML tag to specify where long words would be broken correctly. The Tag is like this&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;wbr&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So one can use it like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;This&amp;#x3C;wbr&gt;is&amp;#x3C;wbr&gt;a&amp;#x3C;wbr&gt;very&amp;#x3C;wbr&gt;long&amp;#x3C;wbr&gt;word&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If this is in place most browser will try to break at these break-points first before breaking anywhere else.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Downside:&lt;/strong&gt; Internet Explorer does not support his at all but at least it doesn’t print the &lt;wbr&gt; tag but ignores it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Downside:&lt;/strong&gt; The words get wrapped at the given places but no dash (“‘-“) will be shown so it still looks kind of incorrect.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;soft-hyphens&quot;&gt;Soft-Hyphens&lt;/h2&gt;
&lt;p&gt;Already the old HTML 3.2 standard defined a character called “soft hyphen”:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x26;shy;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem with this was that not all browser supported it. But the good news seems to be that today finally all browser – even Internet Explorer – added support for the soft-hyphen.&lt;/p&gt;
&lt;p&gt;Using it:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;This&amp;#x26;shy;is&amp;#x26;shy;a&amp;#x26;shy;very&amp;#x26;shy;long&amp;#x26;shy;word&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As it looks to me this solution doesn’t have any downsides yet so I will go with this one.&lt;/p&gt;</content:encoded></item><item><title>Visual Studio 2017 support for ligatures fonts like Fira Code</title><link>https://marcduerst.com/blog/visual-studio-2017-support-for-ligatures-fonts-like-fire-code/</link><guid isPermaLink="true">https://marcduerst.com/blog/visual-studio-2017-support-for-ligatures-fonts-like-fire-code/</guid><description>Based on the post ‘Monospaced Programming Fonts with Ligatures‘ from Scott Hanselman I tried if that works in for the classic Visual Studio too. Short answer...</description><pubDate>Tue, 25 Jul 2017 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: vs2017_ligatures_options.png --&gt;
&lt;!-- MISSING IMAGE: vs2017_ligatures-zoom.png --&gt;
&lt;!-- MISSING IMAGE: vs2017_ligatures.png --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 3 images that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Based on the post &lt;a href=&quot;https://www.hanselman.com/blog/MonospacedProgrammingFontsWithLigatures.aspx&quot;&gt;‘&lt;em&gt;Monospaced Programming Fonts with Ligatures&lt;/em&gt;‘&lt;/a&gt; from &lt;a href=&quot;https://twitter.com/shanselman&quot;&gt;Scott Hanselman&lt;/a&gt; I tried if that works in for the classic Visual Studio too. Short answer: yes, the Ligatures support works out of the box – no settings other then choosing the font is needed.&lt;/p&gt;
&lt;p&gt;Here is some sample TypeScript code written in Visual Studio 2017:&lt;/p&gt;
&lt;h2 id=&quot;how-to-install&quot;&gt;How to install?&lt;/h2&gt;
&lt;p&gt;Install the font on your Windows box like described &lt;a href=&quot;https://github.com/tonsky/FiraCode/wiki&quot;&gt;here&lt;/a&gt;. Then open Visual Studio and go to &lt;em&gt;Tools&lt;/em&gt; &gt; &lt;em&gt;Options&lt;/em&gt; &gt; &lt;em&gt;Fonts and Color&lt;/em&gt; and choose ‘&lt;em&gt;Fira Code&lt;/em&gt;” and press ‘Ok’. That’s it!&lt;/p&gt;
&lt;p&gt;Enjoy the new coding-world with Ligatures!&lt;/p&gt;</content:encoded></item><item><title>Estimations: Story Points vs. Hours</title><link>https://marcduerst.com/blog/estimations-story-points-vs-hours/</link><guid isPermaLink="true">https://marcduerst.com/blog/estimations-story-points-vs-hours/</guid><description>Over the last months the topic of estimations for developing software with many people arise many times. The thing with the story-points for estimations ofte...</description><pubDate>Sun, 23 Jul 2017 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: storypoints_1.png --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 1 image that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Over the last months the topic of estimations for developing software with many people arise many times. The thing with the story-points for estimations often seems to be confusing so lets write about it.&lt;/p&gt;
&lt;h2 id=&quot;why-story-points&quot;&gt;Why Story-Points?&lt;/h2&gt;
&lt;p&gt;When a software developers makes estimates in hours, others (Managers, Customers, Users, etc.) thinks of it as a more or less exact value. But the problem is, that it is really hard to name exact values in software development because each software and each project is different. So most of a developers daily business is doing things or the variation of it for the first time. Its more like an engineer / research style work then repetitive assembly-line style work. Try to ask scientist how long he needs until finished (in hours)?&lt;/p&gt;
&lt;p&gt;So instead of estimate in hours the software industry came up with a new measurement: the Story-Points.&lt;/p&gt;
&lt;h2 id=&quot;what-are-story-points&quot;&gt;What are Story-Points?&lt;/h2&gt;
&lt;p&gt;All and nothing! Its a measurement that does not directly result in hours and its values have different meaning for each team! This is a very important thing: one can’t take the story-points definition from one team to another. Each team has its own understanding of the values used.&lt;/p&gt;
&lt;p&gt;But really, what is it?&lt;/p&gt;
&lt;p&gt;Each backlog-item (aka &lt;em&gt;User-Story&lt;/em&gt; aka &lt;em&gt;To-Do&lt;/em&gt;) gets a story-point value which describe the approximate size of the work. Backlog-items that are about the same size should have the same story-point value. When the team makes an estimate for a new backlog-item they think of which other backlog-item was baout the same size and give it the same story-point values.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Story-Points describe the relative size of a backlog-item to other backlog-items.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-use-story-points&quot;&gt;How to use Story-Points?&lt;/h2&gt;
&lt;p&gt;The questions is what we can do with the Story-Point values if they are no hours and a thing that only the one team understand?&lt;/p&gt;
&lt;p&gt;The team works in sprints (aka &lt;em&gt;iterations&lt;/em&gt;) of 2 to 4 weeks (defined by the team). After a few sprints the team knows how many Story-Points they can do in a sprint by sum the story-point values of the backlog-items they did per sprint. This values is called “Velocity”. Knowing this value allows the team to plan a new sprint by pulling in backlog-items until the total Story-Points reached their velocity (or even better: a little less). If team-members are on holiday etc. the team pulls in less story-points to address the reduced velocity.&lt;/p&gt;
&lt;h2 id=&quot;where-come-the-hours-into-play&quot;&gt;Where come the hours into play?&lt;/h2&gt;
&lt;p&gt;After a team pulled in the backlog-items for a given sprint they plan the details for each of these backlog-items.&lt;/p&gt;
&lt;p&gt;In tools like &lt;em&gt;Microsoft Team Foundation Server&lt;/em&gt; (TFS) or &lt;em&gt;Microsoft Visual Studio Team Services&lt;/em&gt; (VSTS) the team can add “tasks” to each backlog-item. The tasks are a relative small amount of work not more then a few hours. One can easily do an estimate for it in hours. All tasks together get the total hours needed for a backlog-item. All backlog-items together show the total hours for the upcoming sprint.&lt;/p&gt;
&lt;p&gt;Then the team can define work-hours per day and days-off for team-members. This gives the total hours the team has for a sprint. TFS/VSTS can visualize all these values to show if a sprint (and their members) are on-track or go totally off.&lt;/p&gt;
&lt;h2 id=&quot;why-not-directly-create-tasks-and-add-hours-for-all-work&quot;&gt;Why not directly create tasks and add hours for all work?&lt;/h2&gt;
&lt;p&gt;Two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Lot of work:&lt;/strong&gt; For a medium software project it would take weeks a team spend to get all the detailed estimates in hours. No project likes to spend all this time upfront.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Change of plans:&lt;/strong&gt; In software projects its very likely that the plan will change. That’s why the industry came to “&lt;em&gt;agile&lt;/em&gt;” software development but this would be another blog-post. Spending days or weeks making detailed estimates for work that will be dropped before it will started does not make any sense and is a waste of time.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;what-values-to-use-for-story-points&quot;&gt;What values to use for Story-Points?&lt;/h2&gt;
&lt;p&gt;The bigger a backlog-item is the more difficult it is for us humans to estimate exactly. To reflect this many teams use values from the &lt;a href=&quot;https://en.wikipedia.org/wiki/Fibonacci_number&quot;&gt;Fibonacci number&lt;/a&gt; (1, 2, 3, 5, 8, 13, 21, …) only and limit the maximum value to certain value. Backlog-Items that are bigger then this maximum value must be spitted into two or more separate items.&lt;/p&gt;
&lt;h2 id=&quot;but-really-give-me-number&quot;&gt;But really: give me number!&lt;/h2&gt;
&lt;p&gt;Ok, lets see a sample what Story-Point values my colleagues and I often use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1&lt;/strong&gt; = A trivial change with absolutely no risk, should not take longer then 30 minutes&lt;br&gt;
e.g. changing a static text in the UI&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2&lt;/strong&gt; = A small change with absolutely no risk, not longer then 4h&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3&lt;/strong&gt; = Simple change with low risk and takes maximum 1d&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;5&lt;/strong&gt; = Medium change max. 2-3d or small change but with risk&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;8&lt;/strong&gt; = Larger change of max. 5d or change with risk&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;13&lt;/strong&gt; = Large change of max. 2 Weeks or with a decant risk&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Risk:&lt;/strong&gt; with risk I mean the risk a change takes longer then expected because we don’t know exactly how to do it or we for the first time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sprint length:&lt;/strong&gt; we normally use a sprint length of three weeks. So a value of 13 with a max. of two weeks fits into a sprint well. Larger values then 13 don’t exists for our team because with our scale they would not fit into a three week sprint.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I got feedback from multiple people that even “13” means to them: “We are really unsure about this item and will need to further split it for a better estimation”. So normally the items with 13 will be split to multiple items before work starts on these bigger items.&lt;/p&gt;</content:encoded></item><item><title>Trigger TFS and VSTS buildjobs using wildcards</title><link>https://marcduerst.com/blog/trigger-tfs-and-vsts-buildjobs-using-wildcards/</link><guid isPermaLink="true">https://marcduerst.com/blog/trigger-tfs-and-vsts-buildjobs-using-wildcards/</guid><description>In TFS and VSTS one can create a whole list of triggers that particular build-jobs. In the drop-down one can select an existing branch and all done. But if y...</description><pubDate>Mon, 10 Jul 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2017/07/tfsvsts_trigger_cibuild_featurebranches_2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In TFS and VSTS one can create a whole list of triggers that particular build-jobs. In the drop-down one can select an existing branch and all done. But if you like to trigger your CI build-jobs for all feature branches one can use wildcards too.&lt;/p&gt;
&lt;p&gt;Eg. “&lt;strong&gt;feature/*&lt;/strong&gt;”&lt;/p&gt;
&lt;p&gt;To do so you have to expand the drop-down and enter the filter text into the Textbox that looks like a search box. Press ENTER and TFS / VSTS will use exactly this filter. Its not quite intuitive but works.&lt;/p&gt;
&lt;p&gt;See the following screenshots.&lt;/p&gt;</content:encoded></item><item><title>Layer Architecture: Separation of View, Business Logic and Physical Data Access</title><link>https://marcduerst.com/blog/layer-architecture-separation-of-view-business-logic-and-physical-data-access/</link><guid isPermaLink="true">https://marcduerst.com/blog/layer-architecture-separation-of-view-business-logic-and-physical-data-access/</guid><description>This is a topic my colleague and I are discussing a lot the last few weeks because we started a little internal framework/library which should help us buildi...</description><pubDate>Fri, 07 Jul 2017 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: applicationlayermodels.png --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 1 image that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a topic my colleague and I are discussing a lot the last few weeks because we started a little internal framework/library which should help us building small to medium vertical line-of-business web-apps using ASP.Net MVC. Its an old and widely discussed topic in the industry since years: what are your applications layers and what boundary should one use? Where does the presentation layer end, where or how is the business-logic accessed? How separated is it from the physical layer (data-access)?&lt;/p&gt;
&lt;p&gt;There are a lot of layering- and separation-models. Then the more general strategies like Domain-Drive-Design, SOLID, well known patterns like Repository-Pattern or Unit-Of-Work come into play too.&lt;/p&gt;
&lt;p&gt;Most topics result in the conclusion that one should not over engineer the solution and just do what the one application needs and what the customer ordered. That’s good if one just looks at one single application. But we have to do many such applications and therefore go further when specifying the architecture for the next few years and many apps. This then are hard to go for KISS (=keep it simple, stupid) – but we try.&lt;/p&gt;
&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;/h2&gt;
&lt;p&gt;Knowing your requirements is always a good start. So what are our requirements?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The apps should use the same library and concepts so our devs can understand and maintain them easily. Currently each app has its own concepts and new devs need to be trained for each app.&lt;/li&gt;
&lt;li&gt;Fit well for small to medium (10-60 Database Tables) line-of-business apps. They have a lot CRUD but also a decent amount of workflows / business-/domain-logic.&lt;/li&gt;
&lt;li&gt;We not only build API’s but also standard entities and standard MVC UI for these standard entities. For example we have translation entities and optional a whole translation UI as part of the framework.&lt;/li&gt;
&lt;li&gt;We currently work with Entity Framework 6 but will move to Entity Framework Core 2 one day or even move on to document DB’s like MongoDB or Azure Cosmos DB’s in the not so far future. So the physical data-access layer should be decoupled and we like to re-use as much logic and UI’s as we can when replacing the data-access layer.&lt;/li&gt;
&lt;li&gt;The framework/library will be used for multiple apps over the next years as projects come to our table. (we are an IT-Service company in the project business)&lt;/li&gt;
&lt;li&gt;Web-Services (REST etc.) must be supported and building SPA apps e.g. using React is on the horizon.&lt;/li&gt;
&lt;li&gt;We saw that we have to force developers to a clear design/layering otherwise it will mess up (especially if external coders are in the team like near-/off-shoring).&lt;/li&gt;
&lt;li&gt;We like to think of the database like yet another data-storage. We don’t use DB-specific features like stored-procedures etc. – only when there is absolutely no other way.&lt;/li&gt;
&lt;li&gt;Business- / Domain-Logic must be fully unit-testet and stay in the .Net application code.&lt;/li&gt;
&lt;li&gt;Don’t write our own level-level-framework but re-use existing libraries.&lt;/li&gt;
&lt;li&gt;Use ORM’s (object-relational mappers) where possible. Don’t write SQL all over and don’t write our own ORM – even this would be fun 😉 Start with using Entity Framework 6.x and add support for EF Core and others later on – as needed.&lt;/li&gt;
&lt;li&gt;Don’t just separate everything and don’t make every little change a huge effort through 10 layers. We don’t need an enterprise-grad layering (yet 🙂 ). KISS is in our mind.&lt;/li&gt;
&lt;li&gt;The application must NOT be easily switchable from one to another backend (ORM etc) but must be able to choose one at the project start.&lt;/li&gt;
&lt;li&gt;The framework/library must support the all supported backends (EF6/SQL, MongoDB/CosmosDB, EF Core, etc).&lt;/li&gt;
&lt;li&gt;Layers we have in mind:
&lt;ul&gt;
&lt;li&gt;Client-side Presentation (like a Javascript/Typescript ViewModel to do MVVM in the browser).&lt;/li&gt;
&lt;li&gt;Server-side Presentation (like some ASP.Net MVC view-models if needed)&lt;/li&gt;
&lt;li&gt;Business-/Domain-Layer (business-logic).&lt;/li&gt;
&lt;li&gt;Physical data-access (ready and write data into the database or table storage; ORM’s etc).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;layer-variations&quot;&gt;Layer-Variations&lt;/h2&gt;
&lt;p&gt;There are a couple of layer-variations when using an ORM. The following are those that make more or less sense to us. I guess there are about a trillion more variations one could create 🙂&lt;/p&gt;
&lt;p&gt;Application Layers and their models / API’s&lt;/p&gt;
&lt;p&gt;**Server-side View-Models:&lt;br&gt;
**First a note about the server-side view models because I drawn them “a little special”. My experience is that sometimes one does not need to build a 1:1 view-model but can use the entities from the layer below. Sometimes I build a complete custom view-model layer and sometimes I wrap the entities or collections in a view-model and add more data-properties for the view but don’t rebuild all entity-classes. The later is my preferred approach when we talk about server-side view-models. This story is about the same for all the variations and can change easily.&lt;/p&gt;
&lt;p&gt;**Type A:&lt;br&gt;
**Basically define the EF/ORM Entities and use them all over – from repositories (data-access) to the representation. Its simple and every standard .Net / EF developer can participate from its first day on the project. The major downsides we discovered in our first alpha-versions is, that a) all data-backends need to support the single set of entities (EF, Mongo-Client all run on the same entity classes) and b) that not so experienced developers tend to place the business-logic etc. “somewhere” because they can. Layers are not really enforced. Both are no-go for us.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Type B:&lt;/strong&gt;&lt;br&gt;
EF/ORM entities are used for data-access in the repository and given to the domain-layer. Therefore the domain-layer does the mapping from the EF entities to the higher-level business objects. The apps talking to our Domain-Services does get the business-objects (maybe specialised per use-case) and don’t know anything about our ORM entities. A clean separation between presentation and persistence happens. If something changes on the physical-layer the app will not need to know this. The domain-layer can use the ORM entities and things like IQueryable to address complex data-access scenarios and have benefits of the ORM-mindset. On the downside it is more effort comparing to Type 1 as we have an additional model to build, map, test and maintain. It also can result in data-access code within the domain-layer that does not work with all supported ORM/repos.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Type C:&lt;/strong&gt;&lt;br&gt;
Domain-layer and data-access is completely separated with an additional DTO-layer. For me this is a theoretical variation and its again a lot more effort to implement and maintain. We will not go this way – I think.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Type D:&lt;/strong&gt;&lt;br&gt;
This one is similar to Type B but the business-objects go the the data-access layer and the data-access will map to ORM models (if needed at all). If offers great flexibility for implementing the data-access layer but as the mapping is done per data-access its more effort then Type B. An advantage is, that the domain-layer does know nothing about the data-access and has no possibility to run code related to data-access (and also is complete unaware of any ORM feature like change-tracking etc). Therefore advanced data-access scenarios that harder to address with Type D then with Type B.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Type E:&lt;/strong&gt;&lt;br&gt;
This type as a clear separation of the business-objects and the service-facade. The presentation does not know anything about the internals for the domain-layer or the layers below. Its all nicely separated but also a lot of effort to build and maintain (and test). For me this is more a enterprise-style layering and over-architectures for our small to medium apps.&lt;/p&gt;
&lt;p&gt;Our final decision is not yet felt but we tend to go for B or D. What do you think? Did we miss a promising layering we should take into consideration too? Thoughts?&lt;/p&gt;</content:encoded></item><item><title>Microsoft Build 2017 Day 3</title><link>https://marcduerst.com/blog/microsoft-build-2017-day-3-german/</link><guid isPermaLink="true">https://marcduerst.com/blog/microsoft-build-2017-day-3-german/</guid><description>Auch am letzten Tag der BUILD 2017 Konferenz gab es wieder eine menge interessanter und unterhaltsamer Sessions. Einige waren so unterhaltsam, dass man diese...</description><pubDate>Sat, 13 May 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Auch am letzten Tag der BUILD 2017 Konferenz gab es wieder eine menge interessanter und unterhaltsamer Sessions. Einige waren so unterhaltsam, dass man diese schon fast als Nerd-Comedy bezeichnen könnte.&lt;/p&gt;
&lt;h2 id=&quot;entity-framework-20&quot;&gt;&lt;strong&gt;Entity Framework 2.0&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Es kommen einige hilfreiche Erweiterungen. Z.B. das Mapping von komplexen Typen inklusive verschachtelten Typen sieht super gelöst aus. Freue mich darauf. Zudem ist mir aufgefallen, dass es möglich sein müsste, das neue, schlanke EF Core – danke NetStandard – mit “normalen” .Net-Full-Framework zu nutzen. Es müsste möglich sein, ASP.Net 4.6 mit EF Core zusammen zu verwenden. Das muss ich allerdings erst mal noch ausprobieren. Das wäre ein sehr cooler Stack für Projekte die noch nicht auf auf .Net Core/ASP.Net Core können, aber trotzdem schon das schlanke EF Core verwenden wollen. Beispielsweise für einfache Testbarkeit mittels In-Memory Driver oder dem komplett neuen SQL-Generator welcher schlankes, sauberes SQL erzeugt; im Gegensatz zu dem von EF6.&lt;/p&gt;
&lt;h2 id=&quot;zukunft-von-c&quot;&gt;&lt;strong&gt;Zukunft von C#&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Mit C# 7.1 (bis ca. 7.3)  beginnt Microsoft damit für kleinere Spracherweiterungen auch mal einen minor Update zu liefern. Grosse Sprachupdates kommen dann aber voraussichtlich in C# 8.&lt;/p&gt;
&lt;p&gt;Es wird viele hilfreiche Vereinfachung rund um Tuples geben. Einige diesen Features wie z.B. die Objekt-Deconstruction sind aber offen designed sodass sie auch für andere Anwendungszecke eingesetzt werden können.&lt;/p&gt;
&lt;p&gt;Es wird auch einen Release (7.2) geben in welchem low-level Features eingeführt werden, welche z.B. für Xamarin interessant sind. Z.B. Datentypen auf Memory gemappt, sodass nicht immer wieder neu Memory alloziert werden muss.&lt;/p&gt;
&lt;p&gt;Diverse weitere coole Sprachfeatures sind angedacht und werden aktuell konkretisiert. Der Inhalt von C# 8 ist aktuell noch nicht fixiert.&lt;/p&gt;
&lt;h2 id=&quot;signalr-für-aspnet-core&quot;&gt;&lt;strong&gt;SignalR für ASP.Net Core&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Der neue SignalR konnte leider nicht zusammen mit ASP.Net 2.0 in den Preview geschickt werden, da die Geschichte komplizierter und grösser ausfällt aus ursprünglich angenommen. So ist der kommende SignalR auch ein kompletter Rewrite mit einigen Änderungen auch im Konzept.&lt;/p&gt;
&lt;p&gt;So ist der neue SignalR viel modularer und erweiterbarer aufgebaut als der alte. U.a. mit offenen Transport- und Hub-Protokollen sowie Formattern. Es wird auch möglich sein, den SignalR für andere Kanäle als HTTP zu verwenden. Für mich sieht das neue Teil extrem universell aus. Es scheint der richtige Schritt zu sein, hier etwas mehr Zeit zu investieren. Konkret rechnet das Team mit einem Release ca. Q3 2017.&lt;/p&gt;
&lt;h2 id=&quot;modernes-web-front-end-development-mit-vs-2017&quot;&gt;&lt;strong&gt;Modernes Web Front-End Development mit VS 2017&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;VS lernt in der neusten Preview wieder einiges im Web-Tooling dazu. Es wird auch an neuen Templates gearbeitet die nicht nur mit .Net funktionieren (z.B. Static Websites) oder an optimierten Templates welche es sehr einfach machen sollen, z.B. mit VS2017 eine Angular2+ASP.Net WebApi Core App zu entwickeln. Auch IntelliSense kann jetzt viel mehr mit plain Javascript-Files anfangen da es neu auch JDoc Syntax versteht und die Metainformationen dieser Dokus verwendet. Z.B. mit dem aufgeborten TypeScript Kompiler und ESLint kann so die Entwickler-Experience für plain JS stark verbessert werden.&lt;/p&gt;
&lt;p&gt;Dann gibt es da ein neues “Client-side Libraries” Features. Dieses erlaubt dem Entwickler Files aus unterschiedlichen Quellen (NPM, Bower, CDNJS, Filesystem) zu installieren – kein Packetmanager! Das Teil hat aus unserer Sicht Vor- und Nachteile. Wir sind uns hier noch nicht einige ob sich das Teil bewähren wird oder eher die Hintertür für Bastellösungen wird. Die Zeit wird es zeigen.&lt;/p&gt;
&lt;p&gt;Das war es soweit von der BUILD 2017 aus Seattle.&lt;/p&gt;
&lt;p&gt;Future of C#&lt;/p&gt;
&lt;p&gt;Modern Web-Development with VS 2017&lt;/p&gt;
&lt;p&gt;What’s wrong with this pic?&lt;/p&gt;</content:encoded></item><item><title>Microsoft Build 2017 Day 2</title><link>https://marcduerst.com/blog/microsoft-build-2017-day-2/</link><guid isPermaLink="true">https://marcduerst.com/blog/microsoft-build-2017-day-2/</guid><description>Heute war ich an diversen Session. Dazwischen max. 30 Minuten Pause – also ein dichtes Programm. Dabei habe ich die folgenden Themen aufgegriffen.</description><pubDate>Fri, 12 May 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Heute war ich an diversen Session. Dazwischen max. 30 Minuten Pause – also ein dichtes Programm. Dabei habe ich die folgenden Themen aufgegriffen.&lt;/p&gt;
&lt;h2 id=&quot;windows-10&quot;&gt;&lt;strong&gt;Windows 10&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Diverse Updates wurden während der Day 2 Keynote für den kommenden “Fall Creators Update” gezeigt. Einige interessante Sachen und neue Programme wie ReMix sollen dabei sein.&lt;/p&gt;
&lt;h2 id=&quot;mixed-reality&quot;&gt;&lt;strong&gt;Mixed Reality&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Ist ein grosses Thema hier an der Build: Mixed Reality. D.h. man kombiniert die echte Realität mit künstlicher Realität. Z.B. (aber nicht nur) mit der HoloLens. Neu gibt es aus einen Kontroller – eine Art GamePad passend zur HoloLens. Thema wird ziemlich gehype’t.&lt;/p&gt;
&lt;h2 id=&quot;net-net-core-aspnet-und-aspnet-core&quot;&gt;&lt;strong&gt;.Net, .Net Core, ASP.Net und ASP.Net Core&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In den QA-Sessions (Roundtable und .Net Open Q/A Panel) habe ich einige Punkte zu .Net, .Net Core, ASP.Net und ASP.Net Core gehört. Hier ein paar die mir wichtig erscheinen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;.Net Full Framework wird für immer da bleiben inkl. WinForms, WPF, UWP, ASP.Net etc. da es u.a. Teil von Windows ist. Würde es entfernt, wäre Windows kaputt was nicht akzeptabel ist. Hier besteht also kein Drang vom .Net Full-Framework zu wechseln.&lt;/li&gt;
&lt;li&gt;ASP.Net Core 2.0 läuft aktuell nicht mehr auf .Net Full-Framework. Das Team analysiert die Kundenbedürfnisse, ob das noch gebaut werden muss.&lt;/li&gt;
&lt;li&gt;Es könnte sein, dass ein paar ausgewählte Features von ASP.Net Core / MVC Core auf den klassischen .Net Full-Framework 4 Stack zurück portiert werden. Ist aber aktuell noch offen.&lt;/li&gt;
&lt;li&gt;Windows Desktop Frameworks werden aktuell keine neuen Würfe geplant die einmal mehr alles über den Haufen werden würde. UWP bleibt also und wächst weiter. Ebenso WPF und – man staune – WinForms! Einige der neuen Features von Windows sollen auch in WinForms unterstützt werden.&lt;/li&gt;
&lt;li&gt;Mit NetStandard 2.0 soll NetStandard auf Augenhöhe vom .Net Full-Framework sein.&lt;/li&gt;
&lt;li&gt;Wo es Sinn macht werden Bemühungen vom .Net- und vom Xamarin-Team zusammen gelegt. z.B. neuer Xamarin-Linker&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;xamarin&quot;&gt;&lt;strong&gt;Xamarin&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Die XAML-Dialekte werden aktuell als XAML Standard 1.0 vereinheitlicht. Analog NetStandard.&lt;/li&gt;
&lt;li&gt;Xamarin erlaubt jetzt Multi-Prozess Debugging auch über Geräte hinweg. So kann man mit dem neuen Player die App direkt auf dem iPhone ausführen und via VisualStudio oder VisualStudio for Mac die App live debuggen (Remote-Debugging). In der gleichen Session kann man auch z.B. den Backend-Code debuggen.&lt;/li&gt;
&lt;li&gt;Xamarin Forms wurde massiv ausgebaut und erlaubt eine echte Native-Experience.&lt;/li&gt;
&lt;li&gt;Xamarin Forms  wird jetzt auch auf macOs und Windows portiert – also nicht nur Mobile-OS wie iOS und Android.&lt;/li&gt;
&lt;li&gt;Live Player für Xamarin Form UI’s direkt auf dem SmartPhone (iOS oder Android) welcher live auf dem Telefon alle XAML-Änderungen aus Visual Studio oder Visual Studio for Mac darstellt – also nicht im Simulator sondern live auf dem echten Telefon.&lt;/li&gt;
&lt;li&gt;Der neue Embeddinator4000 erlaubt es, C#/.Net Assemblys als native Code zu kompilieren. Diese Libraries können dann im Zielsystem wie echte Libraries verwendet werden. Z.B: Object-C .framework oder Java Packete, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;service-fabric&quot;&gt;&lt;strong&gt;Service Fabric&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In einer Session zur Service Fabric wurde gezeigt, was das Teil so grob alles beinhaltet und das viele andere Azure Services darauf aufsetzen. Die Service Fabric kann auch on-prem betrieben werden und unterstützt neu Docker Container. Zudem wird sie neu als offizielle Container-Orchistrierungs-Software deklariert / verkauft.&lt;/p&gt;
&lt;p&gt;Die Demos mit pro Minute 10’000 neue Windows Containers (=light VM’s) erstellen und 1’000’000 Linux Containers als ein Cluster zu betreiben waren echt beeindruckend.&lt;/p&gt;
&lt;p&gt;Service Fabric muss ich mir definitiv genauer ansehen.&lt;/p&gt;
&lt;h2 id=&quot;visual-studio-2017&quot;&gt;&lt;strong&gt;Visual Studio 2017&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Mit ein paar Extensions kann VS bereits sehr nahe an R# aufgerüstet werden. Evtl. ist es mal wieder eine Versuch den R# abzulösen – wobei man dann allerdings mehrere andere Plugin’s verwenden müsste und ggf. noch eigene Code-Analyzers schreiben müsste.&lt;/p&gt;</content:encoded></item><item><title>Microsoft Build 2017 Day 1</title><link>https://marcduerst.com/blog/microsoft-build-2017-day-1-german/</link><guid isPermaLink="true">https://marcduerst.com/blog/microsoft-build-2017-day-1-german/</guid><description>Der erste Tag der Microsoft BUILD 2017 Konferenz ist für mich um. Zeit ein paar Highlights festzuhalten, was mir besonders geblieben ist. Dabei handelt es si...</description><pubDate>Thu, 11 May 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Der erste Tag der Microsoft BUILD 2017 Konferenz ist für mich um. Zeit ein paar Highlights festzuhalten, was mir besonders geblieben ist. Dabei handelt es sich nur um einen ganz kleinen Ausschnitt aus der riesigen BUILD-Konferenz mit hunderten von Speakers und Tracks.&lt;/p&gt;
&lt;h2 id=&quot;postgresql-und-mysql-als-paas&quot;&gt;PostgreSql und MySQL als PaaS&lt;/h2&gt;
&lt;p&gt;Neu können auf Azure auch PostgreSql und MySQL als managed Datenbanken gebucht werden. Dies beinhaltet alle von Azure gewohnten Funktionen wie Skalierung und volle Wartung mit minimalen Downtimes.&lt;/p&gt;
&lt;h2 id=&quot;azure-cloud-shell&quot;&gt;Azure Cloud Shell&lt;/h2&gt;
&lt;p&gt;Das Azure Kommandozeilen-Interface (CLI) ist neu auch direkt im Browser via Azure Portal verfügbar. Dabei handelt es sich um eine echte Bash-Shell inkl. Cloud-Storage welche via Browser gerendert wird! Krass! Damit nicht genug: es gibt auch eine neue Azure Smartphone App für Admin. In dieser Smart-Phone App kann man ebenfalls die Azure Bash aufrufen und verwenden.&lt;/p&gt;
&lt;h2 id=&quot;azure-ai&quot;&gt;Azure AI&lt;/h2&gt;
&lt;p&gt;Die AI Suite (= künstliche Intelligenz) wurde wieder stark ausgebaut. Es gibt neue Services und für diverse bestehende Services wurden Konfigurierbarkeit eingebaut bzw. erweitert. Basis für alle AI sind u.a. die Daten – viele Daten. Ohne viele Daten keine AI. Diese Daten werden in sog. Graphen gespeichert. Ein Graph ist eine Sammlung von Nodes/Knoten welche untereinander Beziehungen haben. Ein Graph stellt eine Art riesiges Datengeflecht dar welches z.B. als Grundlage für die AI / KI dienen kann.&lt;/p&gt;
&lt;h2 id=&quot;azure-cosmos-db&quot;&gt;Azure Cosmos DB&lt;/h2&gt;
&lt;p&gt;Eine der grossen Ankündigungen war die Verfügbarkeit der neuen Azure Cosmos Datenbank. Nach 15 Jahren Entwicklung und Azure-interem Einsatz ist diese jetzt offen für alle Apps.&lt;/p&gt;
&lt;p&gt;Azure Cosmos DB wird als die 1. weltweit skalierende, multi-model Datenbank bezeichnet. Die Datenbank ist von Anfang an auf massive, weltweite Skalierung ausgelegt worden und kann unterschiedliche Datenbank-Modelle (Key-Value, Document und Graph) bedienen. Darüber liegt ein stetig wachsendes Angebot an API’s. Aktuell u.a. DocuementDB, MongoDB, Gremlin, etc. Die Datenbankbank verfügt über fünf unterschiedliche Konsistenzlevel. Zudem gibt es SLA’s nicht nur für die Verfügbarkeit sondern auf für Antwortzeiten unter 10ms (lesen) und unter 17ms (schreiben). Die Datenbanken können auch grenzenlos wachsen und teile der Datenbank können mit sog. Geo-Fences versehen werden, sodass diese Datenbestände nur in den entsprechenden Ländern gespeichert werden. Für die lokale, offline Entwicklung gibt es den Cosmos DB Emulator.&lt;/p&gt;
&lt;p&gt;Die Cosmos DB hat uns alle drei stark beeindruckt. Wir werden von der Cosmos DB wohl nicht das letzte Mal gehört haben.&lt;/p&gt;
&lt;h2 id=&quot;aspnet-core-20-preview&quot;&gt;ASP.Net Core 2.0 Preview&lt;/h2&gt;
&lt;p&gt;Die Session von Scott Hanselman und Daniel Roth war echt der Hammer! Viel Information und sehr guter Unterhaltungswert.&lt;/p&gt;
&lt;p&gt;Ab sofort ist der Preview von ASP.Net Core 2.0 verfügbar. Dieser sowie auch der passenden Visual Studio 2017 Preview können side-by-side zu den aktuellen, stabilen Versionen installiert werden. Diese Version 2.0 basiert auf dem NetStandard 2.0 welche gem. den Herren jetzt Feature-Even mit dem .Net Full Framework ist. Die Anzahl API’s wurden somit nochmals massiv ausgebaut.&lt;/p&gt;
&lt;p&gt;ASP.Net Core 2.0 bringt viele Vereinfachungen für den Entwickler mit sich. Zudem werden Standard-Funktionen auch übersicht in Helpers aufgelagert. Neu sind die Razor-Pages für einfache Seiten. Man muss damit keinen Controller, View und Model mehr separat machen sondern kann dass alles in einer Razor-Seite abhandelt. Praktisch man den Bedarf nach einer “einfachen Seite” innerhalt der ASP.Net Core MVC App hat.&lt;/p&gt;
&lt;p&gt;ASP.Net Core 2.0 ist jetzt neu auch vorinstalliert mit .Net Core. Das führt dazu, dass die Apps viel schneller starten und auch ein Nuget-Restore sehr schnell von statten geht. Ausserdem muss für die App nicht mehr die ganzen System-DLL’s ausliefern was das Installationspaket sehr viel kleiner macht.&lt;/p&gt;
&lt;h2 id=&quot;visual-studio-for-mac-10&quot;&gt;Visual Studio for Mac 1.0&lt;/h2&gt;
&lt;p&gt;Die erste offizielle Version von Visual Studio for Mac wurde freigegeben. Die IDE ist sehr ausgereift und hat bereits diversen Code (Editor Control, Roslyn, etc.) von Visual Studio 2017 übernommen. Man kann mit Ihr sehr gut Mobile-Apps (iOS, Android, tvOS, watchOS) wie auch Desktop oder Web-Apps entwickeln. Auch die Integration mit Docker und Azure-Publish ist bereits Realität. Visual Studio for Mac macht bereits einen sehr ausgewachsenen Eindruck.&lt;/p&gt;
&lt;p&gt;Das mal so ein paar Eindrücke und Infos vom ersten Tag. Wer zu einem der Themen gerne mehr wissen will, sollte die nächsten Tage mal googeln. Die ganzen Detailinfos werden nah-dis-nah online gestellt.&lt;/p&gt;</content:encoded></item><item><title>Auto-complete Pull Requests with TFS and VSTS</title><link>https://marcduerst.com/blog/auto-complete-pull-requests-with-tfs-and-vsts/</link><guid isPermaLink="true">https://marcduerst.com/blog/auto-complete-pull-requests-with-tfs-and-vsts/</guid><description>At our company we are working mainly with TFS and VSTS using GIT repositories. We also set up our project teams with a Lead-Developer. A Lead-Dev has multipl...</description><pubDate>Wed, 19 Apr 2017 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: pr_autocomplete_1.png --&gt;
&lt;!-- MISSING IMAGE: pr_autocomplete_2.png --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 2 images that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2017/04/pr_autocomplete_3.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;At our company we are working mainly with TFS and VSTS using GIT repositories. We also set up our project teams with a Lead-Developer. A Lead-Dev has multiple responsibilities. One is to keep the technical overview of all of a projects source-code. We also are heavily committed on Code-Reviews. To do so we use TFS/VSTS pull-requests.&lt;/p&gt;
&lt;p&gt;Each feature or bugfix is developed in its own GIT feature branch. A developer can commit to his/her feature branch as often as he/she likes. When the feature is done the Developer places a Pull-Request using the TFS/VSTS web-UI. &lt;a href=&quot;https://www.visualstudio.com/en-us/docs/git/pull-requests&quot;&gt;Here&lt;/a&gt; is a good article on how one can place and handle pull-requests with TFS (but the current versions UI is much improved compared to the version showed in the article). This article is about the “Auto-Complete” feature of TFS/VSTS that I – as a Lead-Dev – really like and are getting used to it.&lt;/p&gt;
&lt;h2 id=&quot;review-comments&quot;&gt;Review comments&lt;/h2&gt;
&lt;p&gt;When I get a pull-request from a Developer it shows me several tabs with all kind of information. On the first tab there is a general comment area – a kind of threaded chat. It also shows the summary of the comments left to the source-code files and updates to the pull-request. Think of it as activity-log of the PR – like Facebook for the PR.&lt;/p&gt;
&lt;p&gt;One can also leave comments with the “Files” tab  directly within source-code. Each comment has a status.&lt;/p&gt;
&lt;p&gt;They are tight to a workflow: a reviewer can leave comments and a developer can look through them and mark their status accordingly. Note: once a pull-request is created, it can be updated by simply do a GIT PUSH to it. Using this technique the code get cleaned and comments can get addressed (or further discussed). If everything is fine a reviewer (or Lead-Dev) can “Approve” the code. If CI-Builds are fine too and the PR is linked to workitems (see TFS “branch policies”) the PR then can be “Completed”. The TFS-/VSTS-Server then will do a GIT MERGE (and optionally “squash” and delete the feature-branch).&lt;/p&gt;
&lt;h2 id=&quot;auto-complete-pull-request&quot;&gt;Auto-Complete Pull-Request&lt;/h2&gt;
&lt;p&gt;As a Lead-Dev of multiple projects and libraries I spent some time in reviewing Pull-Requests. Most of them are of good quality but I have suggestions for improvments. I then can leave my comments as described above and instead of “Approve” the PR I can set it to “Waiting for author”. This means I wait on the fixes or answers from the Developer before accepting the pull-request. If there are no major complains I can set the PR to “Auto Complete”.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2017/04/pr_autocomplete_3.png&quot; alt=&quot;pr_autocomplete_3&quot;&gt;&lt;/p&gt;
&lt;p&gt;This means that if all lights are green (Comments are addressed, build succeed, work-items are linked. no merge-conflicts happen) the pull-request will be completed automatically asap.&lt;/p&gt;
&lt;p&gt;This is a nice time-saver for me as a reviewer / Lead-Dev as I don’t have to re-visit and manually “Complete” this pull-request. The status is also visible to the Developers so they knows if they addresses the issues the PR will get integrated immediately. It also shortens the turnaround time so the PR is completed/integrated faster because they don’t have to get the Lead-Dev / Reviewer to review everything again. The is handy for the whole team as the team has the new code faster and less chance for merge-conflicts exists.&lt;/p&gt;</content:encoded></item><item><title>Thoughts about TagHelpers</title><link>https://marcduerst.com/blog/thoughts-about-taghelpers/</link><guid isPermaLink="true">https://marcduerst.com/blog/thoughts-about-taghelpers/</guid><description>ASP.Net MVC Core introduced the new TagHelpers. The should take the C#-Magic out of the Razor views so people without C# know-how – mainly “the HTML/CSS-only...</description><pubDate>Sat, 01 Apr 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;ASP.Net MVC Core introduced the new &lt;em&gt;&lt;strong&gt;TagHelpers&lt;/strong&gt;&lt;/em&gt;. The should take the C#-Magic out of the Razor views so people without C# know-how – mainly “the HTML/CSS-only Web-Designer” can work on the views too with the tools they know and which don’t understand C#. Also the syntax looks nicer as the developers brain should not switch between C# and HTML all the time. The classic HTML-Helpers still exist. That’s what the advertisements say and it sounds good to me as a C# developer too.&lt;/p&gt;
&lt;p&gt;Here is a sample for those of you never saw the TagHelpers:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Old HTML-Helpers:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@Html.LabelFor(m =&gt; m.MyProperty, new { @class=&quot;col-sm-2 control-label&quot; })&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;New Tag-Helpers:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This label Tag-Helpers looks clean and nice.&lt;/p&gt;
&lt;h2 id=&quot;my-experience-and-thoughts&quot;&gt;My experience and thoughts&lt;/h2&gt;
&lt;p&gt;Now I worked with &lt;em&gt;ASP.Net MVC Core&lt;/em&gt; for a while on my personal projects. After some ramp-up with the new TagHelpers it got easier – that was to be expected. I am far away from an expert or even have a deep background of the TagHelpers but what I noticed: many of them are not easier to work with as they need more brain-power to use as when using the Html-Helpers. But why is this? Ads told us it should be exactly the opposite! This made me think for a while now …&lt;/p&gt;
&lt;p&gt;I noticed that the problem is with the non-trivial TagHelpers. Most TagHelpers are implemented as a custom HTML-Attribute (or a set of attributes) and not on Tag-Level. But this means I have to write the correct HTML-Tag myself and then use the Tag-Helper attribute. Further more this means that I as a developer have to remember two or three but one thing:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Which Tag-Helper exists?&lt;/li&gt;
&lt;li&gt;How could the TagHelper be implemented so:&lt;/li&gt;
&lt;li&gt;Which outer HTML-Tags must I surround what Tag-Helper with?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That’s a lot more brain-work (and brain storage space) I need then with HTML-Helpers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Which HTML-Helpers exists?&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;examples&quot;&gt;Examples&lt;/h3&gt;
&lt;p&gt;Let’s look at an example where I really needed some time to figure out how the TagHelper works and had to ask stack overflow – couldn’t figure it out on my own: Validation Messages.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;With a HTML-Helper straight forward:&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@Html.ValidationMessage(m =&gt; m.MyProperty)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One basically needs brain-power to remember there is something with “….ValidationM….”. The rest is &lt;em&gt;IntelliSense&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Now with Tag-Helpers:&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Beside the fact that this is slightly longer I have to remember / know a few more things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There is a TagHelper with “…validation…”.&lt;/li&gt;
&lt;li&gt;For this helper I have to use a &lt;em&gt;&lt;strong&gt;SPAN&lt;/strong&gt;&lt;/em&gt; tag.&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;&lt;strong&gt;SPAN&lt;/strong&gt;&lt;/em&gt; Tag needs to be normal closed – not self-closing (which is the default of Visual Studio’s auto-complete).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When we come to the validation summary you have to know that you have to use it inside a &lt;em&gt;&lt;strong&gt;DIV&lt;/strong&gt;&lt;/em&gt; tag – not a &lt;em&gt;&lt;strong&gt;SPAN&lt;/strong&gt;&lt;/em&gt; because it builds a &lt;em&gt;&lt;strong&gt;UL&lt;/strong&gt;&lt;/em&gt; and &lt;em&gt;&lt;strong&gt;LI&lt;/strong&gt;&lt;/em&gt; ‘s which can not live inside a &lt;em&gt;&lt;strong&gt;SPAN&lt;/strong&gt;&lt;/em&gt; but can inside a &lt;em&gt;&lt;strong&gt;DIV&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text-danger&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But cool is the simplicity to support your own CSS classes. With HTML-Helpers they where as Microsoft did generate them with their own classes etc.&lt;/p&gt;
&lt;p&gt;There are Tag-Helpers I still couldn’t figure out: &lt;code&gt;@Html.EditorFor()&lt;/code&gt; or &lt;code&gt;@Html.DisplayFor()&lt;/code&gt; (…and all the Editor-Templates).&lt;/p&gt;
&lt;h2 id=&quot;the-htmlcss-only-designer-guy&quot;&gt;The HTML/CSS-only designer guy&lt;/h2&gt;
&lt;p&gt;Then there is this often told HTML/CSS-only designer guy which has some basic HTML-Editor and knows about nothing more then HTML und CSS (and design hopefully). This guy then works on your view and stiles them.&lt;/p&gt;
&lt;p&gt;I just never ever saw a HTML/CSS designer which made up even partially useable / maintainable HTML Markdown. IF you get HTML from a web-designer it mostly looks like shit. I’m always impressed that the browser get their crap looking good.&lt;/p&gt;
&lt;p&gt;I talked to two React.js guys as they have a super cool new feature: JSX/TSX files. They are markup mixed with Javascript / TypeScript. …so Razor for the browser-client.&lt;/p&gt;
&lt;p&gt;I asked them: “&lt;em&gt;Does the HTML/CSS-only designer guys get this syntax? And what about tooling?&lt;/em&gt;“. Both answered: “&lt;em&gt;Forget about this designer-guys – they do not exists like this! And tooling is ok. Its us developers how have to code the views anyway so use a powerful language.&lt;/em&gt;“.&lt;/p&gt;
&lt;h2 id=&quot;closing-words&quot;&gt;Closing words&lt;/h2&gt;
&lt;p&gt;I know, TagHelpers are just one more tool in the Devs toolbox. You can use it but you don’t have to. BUT: There is huge push from ASP.Net Team to TagHelpers for all kind of things. Some of them are cooler and some of them – like the ValidationMessage.&lt;/p&gt;
&lt;p&gt;To be honest, Visual Studio Tooling (with R#) was/is quite ok for the Razor views with Html-Helpers and HTML mixed. I saw cool usages of TAG-Level Tag-Helpers; not attribute-level TagHelpers.&lt;/p&gt;
&lt;p&gt;I’m not yet a complete fan of them. I am thinking forth an back what the ideal “thing” in this are should look like. What do you think?&lt;/p&gt;</content:encoded></item><item><title>How to show IDs in TFS Storys and Tasks</title><link>https://marcduerst.com/blog/how-to-show-ids-in-tfs-storys-and-tasks/</link><guid isPermaLink="true">https://marcduerst.com/blog/how-to-show-ids-in-tfs-storys-and-tasks/</guid><description>I remembered that I saw TFS boards where the ID’s where shown directly within the board and one didn’t need to open each work-item to get it’s ID. I need the...</description><pubDate>Mon, 27 Feb 2017 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: tfs_work_story_w_number3.png --&gt;
&lt;!-- MISSING IMAGE: tfs_work_story_w_number4.png --&gt;
&lt;!-- MISSING IMAGE: tfs_work_story_w_number5.png --&gt;
&lt;!-- MISSING IMAGE: tfs_work_story_w_number6.png --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 4 images that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2017/02/tfs_work_story_w_number.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I remembered that I saw TFS boards where the ID’s where shown directly within the board and one didn’t need to open each work-item to get it’s ID. I need these numbers to mention them in my commit messages so the commits and the work-items get link automatically by TFS/VSTS. As it took me quite some time to find these settings again I decided to write them down.&lt;/p&gt;
&lt;p&gt;First of all we are talking about these little numbers here:&lt;/p&gt;
&lt;p&gt;In TFS 2015 Update 3 they are hidden on the cards by default. To switch them on click the little gray gear icon next to the view filters. Not the gear icon in the header!&lt;/p&gt;
&lt;p&gt;Using this gear icon one can configure the current view – and only the current view. If you like to have the setting on other views (eg. backlog vs sprints) too, you need to do it again in the other view(s).&lt;/p&gt;
&lt;p&gt;Now you get a cool relatively new dialog where you can “Show ID’s” and configure other options like style-/color-rules for your cards and add custom fields etc.&lt;/p&gt;
&lt;p&gt;I have configured some color-rules on my board to show story’s and task marked with some of my tags with other colors. For example “blocked” work-items are rendered as red cards.&lt;/p&gt;
&lt;p&gt;Now, go and pimp your boards!&lt;/p&gt;</content:encoded></item><item><title>Removing unused NuGet packages</title><link>https://marcduerst.com/blog/removing-unused-nuget-packages/</link><guid isPermaLink="true">https://marcduerst.com/blog/removing-unused-nuget-packages/</guid><description>After working with Visual Studio and R# for many years now I discovered this feature just yesterday. Maybe some of you find it useful too.</description><pubDate>Sat, 18 Feb 2017 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: resharper_remove_unused_references_1.jpg --&gt;
&lt;!-- MISSING IMAGE: resharper_remove_unused_references_2.jpg --&gt;
&lt;!-- MISSING IMAGE: resharper_remove_unused_references_3.jpg --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 3 images that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2017/02/resharper_remove_unused_references.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;After working with Visual Studio and R# for many years now I discovered this feature just yesterday. Maybe some of you find it useful too.&lt;/p&gt;
&lt;p&gt;I removed code that was depending on an external Nuget Package. Because the code is gone my project didn’t need the Nuget Package anymore. How to fast and safely remove the references and the package?&lt;/p&gt;
&lt;p&gt;Let’s check the currently installed packages first:&lt;/p&gt;
&lt;p&gt;Instead of opening the Nuget Packagemanager and uninstalling things manually there is faster way: right click on the project in the Solution Explorer and go into R# &lt;em&gt;Refactor&lt;/em&gt; menu. There you’ll find the &lt;em&gt;Remove unused references&lt;/em&gt; menu item.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2017/02/resharper_remove_unused_references.jpg&quot; alt=&quot;resharper_remove_unused_references&quot;&gt;&lt;/p&gt;
&lt;p&gt;This command will show you a dialog where one not only can select the plain assembly references to remove but also the references that come from a installed Nuget Package. This dialog shows a different icon for package references. See the highlighted item.&lt;/p&gt;
&lt;p&gt;Clicking next will remove the selected references. For references that where introduced by an installed package the package is uninstalled too. Means your package folder is cleaned and the package is also removed from the package.config / .csproj.&lt;/p&gt;
&lt;p&gt;The following show that not only the reference but also the package was removed:&lt;/p&gt;
&lt;p&gt;Its a nice timesaver!&lt;/p&gt;</content:encoded></item><item><title>How to debug dynamic JavaScripts in Chrome</title><link>https://marcduerst.com/blog/how-to-debug-dynamic-javascripts-in-chrome/</link><guid isPermaLink="true">https://marcduerst.com/blog/how-to-debug-dynamic-javascripts-in-chrome/</guid><description>If your app is loading HTML with Javascript in there using AJAX these dynamic scripts will not show up in Chrome script-debugger (nor Firefox). They show up ...</description><pubDate>Wed, 08 Feb 2017 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: dynamic_scripts_in_chrome.jpg --&gt;
&lt;!-- MISSING IMAGE: dynamic_scripts_in_edge.jpg --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 2 images that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If your app is loading HTML with Javascript in there using AJAX these &lt;em&gt;dynamic scripts&lt;/em&gt; will not show up in Chrome script-debugger (nor Firefox). They show up in IE 11 and Edge but without name.&lt;/p&gt;
&lt;p&gt;To be able to debug them you can name these scripts using a comment on the end of the script block:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//# sourceURL=PersonMassUpdateTab.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Place this &lt;code&gt;//# sourceURL=....js&lt;/code&gt; code just before the closing script tag.&lt;/p&gt;
&lt;p&gt;After loading this content you’ll see the dynamic script in Chrome’s debugger like this:&lt;/p&gt;
&lt;p&gt;Edge will show it too with name but IE doesn’t:&lt;/p&gt;</content:encoded></item><item><title>Where is the package.config file gone?</title><link>https://marcduerst.com/blog/where-is-the-package-config-file-gone/</link><guid isPermaLink="true">https://marcduerst.com/blog/where-is-the-package-config-file-gone/</guid><description>I just updated to the latest VisualStudio 2017 RC, .Net Core 1.1.1 and worked on a previously started little ASP.Net Core app. I’ve managed Nuget packages fo...</description><pubDate>Sat, 04 Feb 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I just updated to the latest VisualStudio 2017 RC, .Net Core 1.1.1 and worked on a previously started little ASP.Net Core app. I’ve managed Nuget packages for the app by adding and removing packages. When it came to commit my changes I thought the version control must be broken: no changes made to the &lt;em&gt;package.config&lt;/em&gt; file each .Net developer got so used to over the last years.&lt;/p&gt;
&lt;p&gt;After a while I took a closer look at the issue. The &lt;em&gt;package.config&lt;/em&gt; does not exist anymore. But the .csproj file exists again (no project.json anymore) and its format changed. It’s short, really short and no GUID’s in anymore. And hey: here we go – there are the packages, right within the .csproj! Here is a complete .csproj:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;netstandard1.6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    library&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ..\..\..\..\..\..\Users\marc.duerst\.nuget\packages\microsoft.aspnetcore.identity.entityframeworkcore\1.1.0\lib\netstandard1.3\Microsoft.AspNetCore.Identity.EntityFrameworkCore.dll&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.dll&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See the &lt;code&gt;PackageReferences&lt;/code&gt;? So nice and clean. Not only 3rd party packages are in there but also the NetStandard library itself. I also remembered I read about this change a while ago. Microsoft re-invented the .csproj files and dropped the &lt;em&gt;project.json&lt;/em&gt; files introduced with .Net Core 1. More infos &lt;a href=&quot;https://blogs.msdn.microsoft.com/dotnet/2016/12/12/updating-visual-studio-2017-rc-net-core-tooling-improvements/&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;R.I.P. package.config !&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title>SignalR Connection Indicator Reloaded</title><link>https://marcduerst.com/blog/signalr-connection-indicator-reloaded/</link><guid isPermaLink="true">https://marcduerst.com/blog/signalr-connection-indicator-reloaded/</guid><description>Some time ago I’ve written a blog post on how to build a connection indicator using ASP.Net MVC, SignalR and TypeScript. I had to write one again and did an ...</description><pubDate>Wed, 01 Feb 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2017/02/connection_indicator.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Some time ago I’ve written a &lt;a href=&quot;https://marcduerst.com/blog/build-a-signalr-connection-indicator-with-typescript-and-knockout&quot; title=&quot;Build a SignalR Connection Indicator with TypeScript and Knockout&quot;&gt;blog post&lt;/a&gt; on how to build a connection indicator using ASP.Net MVC, SignalR and TypeScript. I had to write one again and did an improved version of the previous one by better using &lt;code&gt;Knockout.js&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The final result looks like the initial graphic. So the connection indicator will change its color and text to reflect the online state of the app.&lt;/p&gt;
&lt;p&gt;It also uses a view-model that is bound using databinding to the DOM elements. So we are talking of a MVVM pattern here. As the basic principal still applies we can go straight to the code.&lt;/p&gt;
&lt;h2 id=&quot;signalr-hub&quot;&gt;SignalR Hub&lt;/h2&gt;
&lt;p&gt;First of all I implemented a very simple SignalR Hub in C# using Visual Studio 2015 “Add new item” dialog:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; System&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; System&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Collections&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Generic&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; System&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Linq&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; System&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Web&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Microsoft&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;AspNet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SignalR&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; WebApplication1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Hubs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ConnectionStateHub&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Hub&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hello&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            Clients.All.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;hello&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;razor-layout&quot;&gt;Razor Layout&lt;/h2&gt;
&lt;p&gt;This time I’ve integrated the connection indicator in the Razor layout &lt;code&gt;_Layout.cshtml&lt;/code&gt; so its rendered on all my pages. The layout is a standard Bootstrap 3 page with Knockout.js loaded. The important part of code is this one:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;navbar-header pull-left connectionStateNav&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;connectionStateContainer&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; style&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;font-size:18px&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;hidden&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;label label-default&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Its basically a Bootstrap label with a &lt;code&gt;span&lt;/code&gt; inside it. I use just these two elements with databinding for &lt;em&gt;Knockout.js&lt;/em&gt;. The outer label binds its CSS class to &lt;code&gt;connectionStateCssClass&lt;/code&gt; while the inner Span binds its text to text to &lt;code&gt;connectionStateText&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;At the bottom of the &lt;code&gt;_Layout.cshtml&lt;/code&gt; I have my TypeScript (Javascript) linked:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;http://~/signalr/hubs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My external script file gets initialized using the following Javascript code at the bottom of the &lt;em&gt;_Layout.cshtml&lt;/em&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    window.connectionState &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; MyApp.Core.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OnlineStateViewModel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ko.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;applyBindings&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(window.connectionState, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;.connectionStateNav&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    window.connectionState.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;startSignalRHub&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;($.connection);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    $&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;#connectionStateContainer&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;removeClass&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;hidden&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It loads my TypeScript code from &lt;em&gt;MyAppOnlineState.js&lt;/em&gt; and the SignalR hub from the virtual reference &lt;em&gt;signalr/hubs&lt;/em&gt;. Then it create a new instance of &lt;code&gt;MyApp.Core.OnlineStateViewModel&lt;/code&gt; and apply the Knockout databinding using the &lt;code&gt;data-&lt;/code&gt; attributes for all elements within my connection state &lt;code&gt;DIV&lt;/code&gt;. Finally the SignalR Hub gets started and the connection indicator shown by removing the &lt;code&gt;hidden&lt;/code&gt; class.&lt;/p&gt;
&lt;h2 id=&quot;viewmodel-onlinestateviewmodel&quot;&gt;Viewmodel OnlineStateViewModel&lt;/h2&gt;
&lt;p&gt;Now you probably as for the &lt;em&gt;MyAppOnlineState.js which is a TypeScript file so its source-code is in *MyAppOnlineState.ts&lt;/em&gt;. Here we go:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyApp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Core&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    export &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OnlineStateViewModel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        private&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connectionStateHub: any;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        private&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; subscriptions: Array&amp;#x3C;Function&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connectionState &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ko.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;observable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connectionStateText &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ko.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;observable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connectionStateCssClass &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ko.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;observable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;info&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; subscribeStateChange&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(callback: Function): void {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.subscriptions &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.subscriptions.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;concat&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(callback);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; startSignalRHub&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(connection: any) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.connectionStateHub &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connection.connectionStateHub;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.connectionStateHub.client.hello &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;info&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;SignalrR: hello() received.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            connection.hub.stateChanged((state: any) =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;connectionStateChanged&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(state));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            connection.hub.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;disconnected&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;                setTimeout&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { connection.hub.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); }, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Restart connection after 5 seconds.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            connection.hub.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; connectionStateChanged&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(state: any): void {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; stateConversion&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Verbinde&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Online&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Neu verbinden&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Offline&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; stateClass&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;label-default&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;label-success&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;label-warning&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;label-danger&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;SignalR state changed from: &quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stateConversion[state.oldState] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot; to: &quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stateConversion[state.newState]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;connectionState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(state.newState);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;connectionStateText&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(stateConversion[state.newState]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;connectionStateCssClass&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;label &quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stateClass[state.newState]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.subscriptions.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(state));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The viewmodel basically sets things up in &lt;code&gt;startSignalRHub&lt;/code&gt;. Important here is the assignment of the eventhandler &lt;code&gt;stateChanged&lt;/code&gt; calls the &lt;code&gt;connectionStateChanged()&lt;/code&gt; function. This one calculates new values for the properties &lt;code&gt;connectionState&lt;/code&gt;, &lt;code&gt;connectionStateText&lt;/code&gt; and &lt;code&gt;connectionStateCssClass&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The viewmodel also features a subscriber mechanism where other scripts can add them so they get notified if a connection state change happens. They can do so by calling the function &lt;code&gt;subscribeStateChange()&lt;/code&gt; with the callback to call in case of the connection state changes.&lt;/p&gt;</content:encoded></item><item><title>Common Service Registry</title><link>https://marcduerst.com/blog/common-service-registry/</link><guid isPermaLink="true">https://marcduerst.com/blog/common-service-registry/</guid><description>Based on my previous blog post “Decouple IoC/DI container when authoring a C# library“ I have written some C# Nuget packages to have that Service Registry th...</description><pubDate>Fri, 23 Dec 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2016/12/register.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Based on my previous blog post &lt;em&gt;“&lt;a href=&quot;https://marcduerst.com/blog/decouple-iocdi-container-when-authoring-a-c-library&quot;&gt;Decouple IoC/DI container when authoring a C# library&lt;/a&gt;“&lt;/em&gt; I have written some C# Nuget packages to have that Service Registry thing easily available in all my C# projects. The package(s) are called “Common Service Registry” (see &lt;a href=&quot;https://www.nuget.org/packages?q=commonserviceregistry&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&quot;packages&quot;&gt;Packages&lt;/h2&gt;
&lt;p&gt;Currently the Common Service Registry (CSR) contains three packages. You mainly need two of them. The one always needed is the &lt;code&gt;CommonServiceRegistry.Core&lt;/code&gt;. It contains the basic interfaces like &lt;code&gt;ICommonServiceRegistry&lt;/code&gt; against which one needs to register its DI needs.&lt;/p&gt;
&lt;p&gt;To finally use the &lt;em&gt;Common Service Registry&lt;/em&gt; one also needs an adapter package that build the bridge between the concrete IoC product you are using and the Common Service Registry.&lt;/p&gt;
&lt;p&gt;The following two adapters are currently available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CommonServiceRegistry.SimpleInjector&lt;/code&gt; for using CSR with &lt;a href=&quot;https://simpleinjector.org/index.html&quot;&gt;Simple Injector&lt;/a&gt; (my favorite)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CommonServiceRegistry.Unity&lt;/code&gt; for using CSR with &lt;a href=&quot;https://github.com/unitycontainer/unity&quot;&gt;Unity&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So you need the Core package and one of the above adapter. If you need an additional adapter please create an &lt;a href=&quot;https://github.com/mduu/CommonServiceRegistry/issues&quot;&gt;issue&lt;/a&gt; over on GitBub.&lt;/p&gt;
&lt;h2 id=&quot;how-to-use&quot;&gt;How to use&lt;/h2&gt;
&lt;p&gt;Check out the &lt;em&gt;&lt;a href=&quot;https://github.com/mduu/CommonServiceRegistry#how-to-use&quot;&gt;how to use&lt;/a&gt;&lt;/em&gt; over at GitHub. Its really easy to use that thing. The application needs one additional line and the library needs no additional lines of code (comparing to register without Common Service Registry).&lt;/p&gt;
&lt;h2 id=&quot;writing-an-adapter&quot;&gt;Writing an adapter&lt;/h2&gt;
&lt;p&gt;A new adapter can be implemented with minimal effort. See the source-code of the other adapters (eg. &lt;a href=&quot;https://github.com/mduu/CommonServiceRegistry/blob/master/src/CommonServiceRegistry.SimpleInjector/SimpleInjectorCommonServiceRegistryAdapter.cs&quot;&gt;this one&lt;/a&gt;). Note that each adapter also should have its unit-test assembly and that there is a base-class for adapter tests. So writing unit-tests for new adapters is done with a few lines of code as you can see &lt;a href=&quot;https://github.com/mduu/CommonServiceRegistry/blob/master/src/CommonServiceRegistry.SimpleInjector.Tests/SimpleInjectorCommonServiceRegistryAdapterTests.cs&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;contribute&quot;&gt;Contribute!&lt;/h2&gt;
&lt;p&gt;Contributions are very welcome. If you like to check out (or fork) the source-code you’ll find it on &lt;a href=&quot;https://github.com/mduu/CommonServiceRegistry&quot;&gt;here&lt;/a&gt; GitHub. You can have a look at the issues and pick one to work on.&lt;/p&gt;</content:encoded></item><item><title>Testability for Dynamics CRM SDK Code - Part 2</title><link>https://marcduerst.com/blog/testability-for-dynamics-crm-sdk-code-part-2/</link><guid isPermaLink="true">https://marcduerst.com/blog/testability-for-dynamics-crm-sdk-code-part-2/</guid><description>In Part 1 I showed how I code against the Dynamics CRM SDK with my own ICrmSession and how I can do unit-testing based on those few interfaces and classes. I...</description><pubDate>Wed, 14 Dec 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2016/10/microsoft_dynamics_crm_logo.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://marcduerst.com/blog/testability-for-dynamics-crm-sdk-code&quot;&gt;Part 1&lt;/a&gt; I showed how I code against the Dynamics CRM SDK with my own &lt;code&gt;ICrmSession&lt;/code&gt; and how I can do unit-testing based on those few interfaces and classes. In this second part I’d like to cover some more topics the reader may find interesting.&lt;/p&gt;
&lt;h2 id=&quot;testing-executionrequests&quot;&gt;Testing ExecutionRequests&lt;/h2&gt;
&lt;p&gt;When coding agains the Dynamics CRM SDK from outside of CRM (like for data import/update services) one likes to do multiple data updates within one atomic transaction. The only way I found to do is to build an &lt;code&gt;ExecuteTransactionRequest&lt;/code&gt; and fill its &lt;code&gt;Requests&lt;/code&gt; collection with &lt;code&gt;CreateRequest&lt;/code&gt; and &lt;code&gt;UpdateRequest&lt;/code&gt; instances. Then fire this &lt;code&gt;ExecuteTransationRequest&lt;/code&gt; using &lt;code&gt;OrganizationContext.Execute()&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;Here is some sample code I’ve built on top of my &lt;code&gt;ICrmSession&lt;/code&gt; as discussed in my &lt;a href=&quot;https://marcduerst.com/blog/testability-for-dynamics-crm-sdk-code&quot;&gt;previous post&lt;/a&gt;. Its a simplified version of my code just to point out the basic principe how I send Insert’s and Update’s to Dynamics CRM. Code like this I have used in my base-class for Upsert-Services (one per Entity).&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; virtual&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationResponse&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; DoUpsert&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ICrmSession&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; session&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TUpsertData&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; upsertData&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; entityIdentification&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IQueryable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Func&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;initNewEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Action&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TUpsertData&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;updateEntityFields&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (session &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(session)); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (upsertData &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(upsertData)); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ExecuteTransactionRequest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                Requests &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationRequestCollection&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                ReturnResponses &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // Update existing&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; entityExists&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; existingEntity&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; query)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                entityExists &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;                updateEntityFields&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(updateEntity, upsertData);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                updateEntity.Id &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; existingEntity.Id;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                updateEntity.EntityState &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; EntityState.Changed;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                request.Requests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; UpdateRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { Target &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; updateEntity });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // Insert connection-object if no one did exist&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;entityExists)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; newEntity&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; initNewEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;                updateEntityFields&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(newEntity, upsertData);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                request.Requests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CreateRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { Target &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; newEntity });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            try&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; session.OrganizationService.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Execute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(request);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            catch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;FaultException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OrganizationServiceFault&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ex&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;                // TODO: Log the exception&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                throw&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As discussed the main point is to build a &lt;code&gt;ExecuteTransactionRequest&lt;/code&gt; containing &lt;code&gt;CreateRequest&lt;/code&gt; and &lt;code&gt;UpdateRequest&lt;/code&gt; instances. Then I fire it using &lt;code&gt;session.OrganizationService.Execute()&lt;/code&gt;. The important thing here is that I use my &lt;code&gt;ICrmSession&lt;/code&gt; to get the organization service.&lt;/p&gt;
&lt;p&gt;With this code in place I can easily unit-test without the need for a real Dynamics CRM connection. To do so I can re-use my &lt;code&gt;CrmSessionTestBase&lt;/code&gt; class I showed already in the previous post:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; abstract&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionTestBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFake&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IOrganizationService&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrgService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SetUp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SetUpCrmSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        CrmSession &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TearDown&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; TearDownCrmSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        CrmSession&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Dispose&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        CrmSession &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This unit-test baseclass creates a fake of &lt;code&gt;ICrmSession&lt;/code&gt; which records the sent organization requests using a dynamic fake built with the &lt;em&gt;Fake It Easy&lt;/em&gt; library. Here is the &lt;code&gt;CrmSessionFake&lt;/code&gt; code. For more information read the previous post.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; System&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; System&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Collections&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Generic&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; FakeItEasy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Microsoft&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Xrm&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Sdk&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Microsoft&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Xrm&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Sdk&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Client&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmTests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// Fake of a &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ICrmSession&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; that can be used for unit-testing.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;seealso&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ICrmSession&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ICrmSession&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            OrganizationService &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SetUpOrganizationServiceFake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            OrganizationServiceContext &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SetUpOrganizationServiceContextFake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Gets the &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;OrganizationRequest&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&apos;s that where sent using &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;OrganizationService&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// or &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;OrganizationServiceContext&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The sent &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;OrganizationRequest&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&apos;s.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IList&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OrganizationRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SentOrganizationRequests&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OrganizationRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Gets the organization service.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The organization service.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;seealso&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;IOrganizationService&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IOrganizationService&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Gets the typed organization service context.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The organization service context.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;seealso&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ICrmSession.OrganizationServiceContext&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Dispose&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        IOrganizationService&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SetUpOrganizationServiceFake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; result&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; A.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Fake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IOrganizationService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // Record all call OrganizationRequest&apos;s sent to .Execute() in SentOrganizationRequests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            A.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CallTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Execute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(A&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OrganizationRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;._))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ReturnsLazily&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OrganizationRequest&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                    SentOrganizationRequests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(request);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                    return&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationResponse&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                        Results &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ParameterCollection&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                        ResponseName &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Guid.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NewGuid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ToString&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SetUpOrganizationServiceContextFake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; result&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; A.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Fake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            A.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CallTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(result)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Where&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; call.Method.Name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;CreateQuery&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;WithNonVoidReturnType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CallsBaseMethod&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The important point here is that each unit-test that inherits from &lt;code&gt;CrmSessionTestBase&lt;/code&gt; has a property &lt;code&gt;CrmSession&lt;/code&gt; which is of type &lt;code&gt;ICrmSession&lt;/code&gt; (interface). It is set up with a fake so it records all call to &lt;code&gt;OrganizationService.Execute()&lt;/code&gt; within the property &lt;code&gt;SendOrganizationRequests&lt;/code&gt; for later use.&lt;/p&gt;
&lt;p&gt;So my final unit-tests are as simple as this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TestFixture&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyUpsertServiceTests&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CrmSessionTestBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Test&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Test_InsertNewEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // Arrange&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; upsertData&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CreateUpsertData&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; service&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyUpsertService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // Act&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; organizationResponse&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; service.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Upsert&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CrmSession, upsertData);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // Assert&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            ValidateEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CreateRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(organizationResponse, upsertData);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Test&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Test_UpdateExistingEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // Arrange&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; upsertData&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CreateUpsertData&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // Call to OrganizationContext.CreateQuery() would return a fix (aka existing) is_contractaccount&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            A.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CallTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CrmSession.OrganizationServiceContext)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Where&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x.Method.Name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;CreateQuery&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;WithReturnType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IQueryable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MyEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ReturnsLazily&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MyEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CreateEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(upsertData) }.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;AsQueryable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; service&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyUpsertService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // Act&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; organizationResponse&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; service.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Upsert&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CrmSession, upsertData);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // Assert&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            ValidateEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;UpdateRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(organizationResponse, upsertData);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, this is a simplified version of my code as I did a generic implementation of this for re-use with all of my Upsert-Services but it should show the important parts.&lt;/p&gt;
&lt;p&gt;Two things to point out here:&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Test_UpdateExistingEntity()&lt;/code&gt; highjack the query execution by faking the result for calls to &lt;code&gt;OrganizationServiceContext.CreateQuery()&lt;/code&gt;. This is done with &lt;em&gt;Fake It Easy&lt;/em&gt; again. See &lt;a href=&quot;http://fakeiteasy.readthedocs.io/en/stable/quickstart/&quot;&gt;here&lt;/a&gt; for more samples and a quickstart with &lt;em&gt;Fake It Easy&lt;/em&gt;. I highly recommend getting used to a smart fake/mock library like &lt;em&gt;Fake It Easy&lt;/em&gt;. It can help you so much for unit-testing.&lt;/p&gt;
&lt;p&gt;The second thing is the &lt;code&gt;ValidateEntity()&lt;/code&gt; method. I use it to check if the right requests would have been triggered by my upsert service. Means, I am checking if &lt;code&gt;CreateRequest&lt;/code&gt; or &lt;code&gt;UpdateRequest&lt;/code&gt; are triggered and with what entity data (&lt;code&gt;upsertData&lt;/code&gt;). First my implementation which needs some Reflection hacking:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ValidateEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TExpectedRequestType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OrganizationResponse&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; organizationResponse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TUpsertData&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; upsertData&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    where&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; TExpectedRequestType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OrganizationRequest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    organizationResponse.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Should&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NotBeNull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    CrmSession.SentOrganizationRequests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Should&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;HaveCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    CrmSession.SentOrganizationRequests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;First&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Should&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;BeOfType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ExecuteTransactionRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        ((&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ExecuteTransactionRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)CrmSession.SentOrganizationRequests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;First&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()).Requests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Should&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;HaveCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ((&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ExecuteTransactionRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)CrmSession.SentOrganizationRequests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;First&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()).Requests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;First&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Should&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;BeOfType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TExpectedRequestType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TExpectedRequestType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)((&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ExecuteTransactionRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) CrmSession.SentOrganizationRequests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;First&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()).Requests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;First&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // HACK: Get the entity out of the &quot;Target&quot; property&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; requestType&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; request.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GetType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; propType&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; requestType.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GetProperty&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Target&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; entity&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)propType.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GetValue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(request);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    ValidateEntityContent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(upsertData, entity);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first few lines validate and extract the requests from &lt;code&gt;CrmSession.SentOrganizationRequests&lt;/code&gt;. No Rocket Science here.&lt;/p&gt;
&lt;p&gt;Then the tricky part is to get the entity data out of either &lt;code&gt;CreateRequest&lt;/code&gt; or &lt;code&gt;UpdateRequest&lt;/code&gt; in a generic way. The problem here is, that both have a property called &lt;code&gt;Target&lt;/code&gt; which holds the entity but sadly the Dynamics CRM SDK API is not very well crafted here. The base class of &lt;code&gt;CreateRequest&lt;/code&gt; and &lt;code&gt;UpdateRequest&lt;/code&gt; is the general purpose &lt;code&gt;OrganizationRequest&lt;/code&gt; which does not have a &lt;code&gt;Target&lt;/code&gt; property. There is no common base class like TargetedOrganizationRequests. The Microsoft Team just copy-pasted the &lt;code&gt;Target&lt;/code&gt; property to both classes. Even worst, they made both classe &lt;em&gt;sealed&lt;/em&gt; so they can not be “fixed” from outside outside by re-introduce at least a shared interface for the &lt;code&gt;Target&lt;/code&gt; property.&lt;/p&gt;
&lt;p&gt;Long story short: the only way I was able to address this using generic code (without using copy-paste) was to use the Hack with Reflection. Its a shame but better then copy-paste like Microsoft Dynamics did.&lt;/p&gt;
&lt;h2 id=&quot;updating-and-restoring-data-on-dynamics-crm-during-unit-tests&quot;&gt;Updating and restoring data on Dynamics CRM during unit-tests&lt;/h2&gt;
&lt;p&gt;Sometimes the above faked CRM-connectivity are not enough. The problem is that you only test what you code will fire against Dynamics CRM but you don’t test the reaction of CRM. For example if Dynamics CRM for some reason don’t accept the data you send this would not be covered with the above kind of unit-tests.&lt;/p&gt;
&lt;p&gt;To address these kind of scenarios I added some tests that do more of an integration-tests kind of unit-tests (black-box instead of white-box testing).&lt;/p&gt;
&lt;p&gt;To do so I use a baseclass for my unit-tests that does not use &lt;code&gt;CrmSessionFake&lt;/code&gt; but a real &lt;code&gt;CrmSession&lt;/code&gt; instances. These tests then connect to the projects DEV-Instance of Dynamics CRM Server and do real data-update.&lt;/p&gt;
&lt;p&gt;The problem here is again that the CRM SDK greatly laks of clean transaction support. There is no *begin-commit-rollback” transaction style API. So the common pattern to just open a database transaction before the testing code runs and then always rollback the transaction at the end of the unit-test doesn’t work here.&lt;/p&gt;
&lt;p&gt;I address it in a more classic &lt;em&gt;scrappy&lt;/em&gt; way by doing a try-finally and delete the data I’ve just created again. This requires a few things so it is at least a little bit stable:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Each test-run should create its own unique set of data so the clean-up code can identify the data it needs to delete.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update of existing records can not be easily be undo (eg. if other testrun runs in parallel). So create your unique test-data before and then test the updating with the create test-data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Build re-usable helpers to clean up the data.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;My pattern for these kind of tests goes like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Generate testdata&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; updateData&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyData&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{ MyNumber &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; $&quot;Test_&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Random&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Next&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;9999&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;)}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GenerateUpdateData&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(updateData);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;try&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // Run testcode which updates the real CRM data in here ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;finally&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // Clean up&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    RemoveEntities&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CreateQuery&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(s, updateData.MyNumber ));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally my little helper method &lt;code&gt;RemoveEntities&lt;/code&gt; which I placed in my unit-tests baseclass:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RemoveEntities&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Func&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ICrmSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IQueryable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;queryBuilder&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; TEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Entity&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    using&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; session&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; SessionFactory.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CreateSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; entity&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; queryBuilder&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(session))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            session.OrganizationServiceContext.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;DeleteObject&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(entity, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        session.OrganizationServiceContext.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SaveChanges&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(SaveChangesOptions.ContinueOnError);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It gets a &lt;code&gt;ICrmSession&lt;/code&gt; from my session factory and calls the &lt;code&gt;queryBuilder&lt;/code&gt; delegate (Lambda etc.) to get a query. Then it loads the results from the query and deletes each of them using &lt;code&gt;OrganizationServiceContext.DeleteObject()&lt;/code&gt;. Finally the changes get saved using the &lt;code&gt;SaveChanges()&lt;/code&gt; method.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;If one spends a few hours once to introduce a few basic classes and interfaces things later get easy to work with. In my case having the &lt;code&gt;ICrmSession&lt;/code&gt; and “SessionTestBase class opens up a whole lot of possibillities. So when starting with a new project take your time – you will easily save it later on.&lt;/p&gt;</content:encoded></item><item><title>Testability for Dynamics CRM SDK Code</title><link>https://marcduerst.com/blog/testability-for-dynamics-crm-sdk-code/</link><guid isPermaLink="true">https://marcduerst.com/blog/testability-for-dynamics-crm-sdk-code/</guid><description>During the last months I had to code several web-cervices (ASP.Net WCF Service) for connecting other pieces of software with Dynamics CRM. I’ve used the Dyna...</description><pubDate>Wed, 26 Oct 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2016/10/microsoft_dynamics_crm_logo.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;During the last months I had to code several web-cervices (ASP.Net WCF Service) for connecting other pieces of software with Dynamics CRM. I’ve used the Dynamics CRM SDK (2011, 2015 and 2016) to access CRM from within my C# code.&lt;/p&gt;
&lt;p&gt;For those of you who don’t know the Dynamics CRM SDK: it’s a bunch of .Net libraries (and tools) you can use in your C# code to query and update data and metadata in Dynamics CRM.&lt;/p&gt;
&lt;p&gt;It provides not only one way to access CRM but about three or four. One is a typed Linq API similar to the EntityFramework where one uses generated C# classes and a fluent API. Another one is accessing CRM untyped using string identifiers for entity and fields names. The third option is to build a transaction style API where one build a transaction request object contains create and update requests. One then executes this request using the SDK and CRM will (try) executing all the contained create and update statements within one transaction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; For code running outside of Dynamics CRM the transaction request allows you to get multiple write-operations executed within one transaction.&lt;/p&gt;
&lt;h2 id=&quot;problems&quot;&gt;Problems&lt;/h2&gt;
&lt;p&gt;Connecting to CRM is not quite easy and if you are connected you get multiple objects for accessing CRM (typed and untyped API’s). There is no clean session object.&lt;/p&gt;
&lt;p&gt;As unit-testing my code is a must have for my daily work I quickly ran into the issue how to test my Dynamics CRM code. In the first spot this seems tricky as your code highly depends on the existence of Dynamics CRM. There are some caveats in SDK itself like sealed classes, missing interfaces and missing common base classes.&lt;/p&gt;
&lt;h2 id=&quot;session-handling&quot;&gt;Session-Handling&lt;/h2&gt;
&lt;p&gt;As a start for my upcoming business logic I like to have a nice disposable session object which provides access to miscellaneous parts of the CRM SDK. I also like to have a easy to use factory for creating sessions (connections). All of this should be ready for the &lt;a href=&quot;https://en.wikipedia.org/wiki/Inversion_of_control&quot;&gt;inversion of control (IoC) pattern&lt;/a&gt; using &lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_injection&quot;&gt;Depencendy Injection (DI)&lt;/a&gt;. More precisely for using &lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_injection#Constructor_injection&quot;&gt;&lt;em&gt;constructor injection&lt;/em&gt;&lt;/a&gt; which is my prevered way of how to do DI.&lt;/p&gt;
&lt;p&gt;This means that I have to use C# interfaces and constructor parameters requesting the interfaces they need and depend on.&lt;/p&gt;
&lt;h2 id=&quot;lets-code&quot;&gt;Let’s code!&lt;/h2&gt;
&lt;p&gt;First, the Session interface and implementation which holds the SDK’s &lt;em&gt;OrganizationContext&lt;/em&gt; and &lt;em&gt;OrganizationService&lt;/em&gt;:&lt;/p&gt;
&lt;h3 id=&quot;icrmsession-interface&quot;&gt;ICrmSession Interface:&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// Wraps the xRM &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;IOrganizationService&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; and &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;OrganizationServiceContext&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// in a session that gets disposed correctly.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;remarks&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;Make sure you use &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;using&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt; or call &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;IDisposable.Dispose&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; manually!&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;remarks&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ICrmSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IDisposable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// Gets the organization service.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The organization service.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;seealso&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;IOrganizationService&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    IOrganizationService&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// Gets the typed organization service context.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The organization service context.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;seealso&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;OrganizationServiceContext&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then the implementation of &lt;code&gt;ICrmSession&lt;/code&gt; which also implements the &lt;code&gt;IDisposable&lt;/code&gt; interface. Note that my code uses C# 6 features. If you target an older version of C# you have to do some minor changes to the code.&lt;/p&gt;
&lt;h3 id=&quot;crmsession-implementation&quot;&gt;CrmSession Implementation:&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// Wraps the xRM  and &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// in a session that gets disposed correctly.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ICrmSession&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IOrganizationService&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; organizationService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; organizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (organizationService &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(organizationService));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (organizationServiceContext &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(organizationServiceContext));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        OrganizationService &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; organizationService;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        OrganizationServiceContext &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; organizationServiceContext;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IOrganizationService&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Dispose&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        Dispose&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        GC.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SuppressFinalize&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    protected&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; bool&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IsDisposed&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    protected&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; virtual&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Dispose&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; disposing&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;IsDisposed)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Dispose&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            OrganizationServiceContext &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            (OrganizationService &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IDisposable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Dispose&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            OrganizationService &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            IsDisposed &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ~&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CrmSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        Dispose&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing too fancy so far. Now we need a factory to easily create such &lt;code&gt;ICrmSession&lt;/code&gt; instances. First we need an interface again.&lt;/p&gt;
&lt;h3 id=&quot;icrmsessionfactory-interface&quot;&gt;ICrmSessionFactory Interface:&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ICrmSessionFactory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// Creates a new session and connects to the CRM instance.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    ICrmSession&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CreateSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now the implementation of &lt;code&gt;ICrmSessionFactory&lt;/code&gt;. It creates the &lt;code&gt;OrganizationServiceProxy&lt;/code&gt; and &lt;code&gt;OrganizationServiceContext&lt;/code&gt; CRM SDK which are used to connect to CRM. it also configures the support for the typed proxy classes and finally construct a &lt;code&gt;CrmSession&lt;/code&gt; instance with the all of this.&lt;/p&gt;
&lt;h3 id=&quot;crmsessionfactory-implementation&quot;&gt;CrmSessionFactory Implementation:&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// Implements &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ICrmSession&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; against Dynamics CRM.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFactory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ICrmSessionFactory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Uri&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; defaultOrgUri&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ClientCredentials&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; defaultOrgCredentials&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFactory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ICrmSessionFactoryConfig&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (config &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(config)); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        defaultOrgUri &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; config.ServerUri;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        defaultOrgCredentials &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; config.Credentials;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    internal&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFactory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Uri&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; defaultOrgUri&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ClientCredentials&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; defaultOrgCredentials&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (defaultOrgUri &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(defaultOrgUri)); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.defaultOrgUri &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; defaultOrgUri;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.defaultOrgCredentials &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; defaultOrgCredentials;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;inheritDoc&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ICrmSession&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CreateSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; organizationServiceProxy&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationServiceProxy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(defaultOrgUri, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, defaultOrgCredentials, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; organizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(organizationServiceProxy);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        organizationServiceProxy.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;EnableProxyTypes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(organizationServiceProxy, organizationServiceContext);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above should look familiar to CRM developers. As our factory does have a constructor that takes a configuration object we now need the interface and implementation for that. Later on we can use this configuration object to configure our factory instances right from the DI container.&lt;/p&gt;
&lt;h3 id=&quot;icrmsessionfactoryconfig-interface-for-easy-configuration-of-the-factory&quot;&gt;ICrmSessionFactoryConfig Interface for easy configuration of the factory&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ICrmSessionFactoryConfig&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    Uri&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ServerUri&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    ClientCredentials&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Credentials&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;crmsessionfactoryconfig-implementation&quot;&gt;CrmSessionFactoryConfig Implementation&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFactoryConfig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ICrmSessionFactoryConfig&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFactoryConfig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; orgUrl&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; orgUsername&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; orgPassword&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(orgUrl)) { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(orgUrl)); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (orgUsername &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(orgUsername)); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        ServerUri &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Uri&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(orgUrl);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        Credentials &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ClientCredentials&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            UserName &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                UserName &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; orgUsername,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                Password &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; orgPassword,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Uri&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ServerUri&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ClientCredentials&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Credentials&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So far the above code is generic. We can but it into a central library for reuse in other apps and projects. Build a Nuget package for it allows you to easily update it later on.&lt;/p&gt;
&lt;h3 id=&quot;example-on-how-to-use-the-sessions&quot;&gt;Example on how to use the sessions&lt;/h3&gt;
&lt;p&gt;Now I can create and use the session like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFactoryConfig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;&amp;#x3C;orgurl&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;&amp;#x3C;orgusername&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;orguserpwd&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; factory&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFactory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(config);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; session&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; fatory.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CreateSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    var query session.OrganizationServiceContext&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CreateQuery&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MyEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Where&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p.Firstname &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;John&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; After leaving the &lt;code&gt;using&lt;/code&gt; scope the &lt;code&gt;CrmSession&lt;/code&gt; and therefore the connection to the CRM gets disposed automatically.&lt;/p&gt;
&lt;p&gt;This code is clean but did not save a lot of lines of code. But we now have a clear separation in place (decoupling).&lt;/p&gt;
&lt;h3 id=&quot;example-for-using-with-dependency-injection-di&quot;&gt;Example for using with Dependency Injection (DI)&lt;/h3&gt;
&lt;p&gt;As we have everything decoupled nicely we now can inject them using &lt;em&gt;Dependency Injection&lt;/em&gt;. To do so add a DI container and configure it somewhere in your applications startup. The following code show how to register a `ICrmSessionFactoryConfig&lt;code&gt;singleton instance and the&lt;/code&gt;ICrmSessionFactory“ using &lt;a href=&quot;http://simpleinjector.org&quot;&gt;SimpleInjector&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; container&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Container&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ICrmSessionFactoryConfig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFactoryConfig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(crmwsConfig.OrgUrl, crmwsConfig.OrgUser, crmwsConfig.OrgPassword));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ICrmSessionFactory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CrmSessionFactory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// TODO: Add other type registrations here&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// TODO: Use this container to create the instances of your root objects (see container documentation)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note 1:&lt;/strong&gt; Using other DI containers like Unity, DryLock, Ninject, etc. is basically the same but may vary in the syntax.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note 2:&lt;/strong&gt; Beside creating and configuring the DI container you must make sure that the instances of your objects do get created by your DI container so the constructor injection is in place. How this is done depends on the type of application and which DI container you are using. See your DI container documentation and samples for More information. There probably is a Nuget package for your container and type of application to set up these things automatically.&lt;/p&gt;
&lt;p&gt;With this registration in place I’ve build my service classes containing the logic like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IMyService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Serve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IMyService&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ICrmSessionFactory&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; sessionFactory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyLogic&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ICrmSessionFactory&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; sessionFactory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (sessionFactory &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(sessionFactory)); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.sessionFactory &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sessionFactory;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;inheritdoc&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; virtual&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; void Serve&gt;(string name)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        using&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; session&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sessionFactory.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CreateSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ExecuteTransactionRequest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                Requests &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationRequestCollection&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                ReturnResponses &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; newEntity&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                Name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            request.Requests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CreateRequest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            { &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                Target &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                { &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                    ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;. &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                } &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            session.OrganizationService.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Execute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(request);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I also registered &lt;code&gt;IMyService&lt;/code&gt; with my DI container so one level up&lt;br&gt;
(for example in your WebAPI controller) you can request an instance of MyService using constructor parameters too.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; HomeController&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IMyService&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; myService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; HomeController&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IMyService&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; myService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (myService &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(myService)) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.myService &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; myService;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ActionResult&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Index&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        myService.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Serve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;unit-testing&quot;&gt;Unit-Testing&lt;/h2&gt;
&lt;p&gt;The above was pretty straight forward and gives us a nice layer of abstraction and decoupling. With this in place Unit-Testing of your service logic in `MyController“ can be done by faking or mocking the ICrmSession. This way we do not need a Dynamics CRM running and get lighting fast unit-tests.&lt;/p&gt;
&lt;p&gt;To do so I created myself a mock-class for &lt;code&gt;ICrmSession&lt;/code&gt; which I can reuse in other apps and projects. It basically catches all call to &lt;code&gt;OrganizationContext.Execute()&lt;/code&gt; and records them in the property &lt;code&gt;SentOrganizationRequests&lt;/code&gt;. To set up the fakes for &lt;code&gt;IOrganizationService&lt;/code&gt;&lt;br&gt;
and &lt;code&gt;OrganzationContext&lt;/code&gt; I use my favorite faking library &lt;a href=&quot;http://fakeiteasy.github.io&quot;&gt;Fake it easy&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;crmsessionfake-implementation&quot;&gt;CrmSessionFake Implementation&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; System&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; System&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Collections&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Generic&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; FakeItEasy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Microsoft&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Xrm&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Sdk&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Microsoft&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Xrm&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Sdk&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Client&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmTests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// Fake of a &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ICrmSession&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; that can be used for unit-testing.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;seealso&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ICrmSession&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ICrmSession&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            OrganizationService &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SetUpOrganizationServiceFake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            OrganizationServiceContext &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SetUpOrganizationServiceContextFake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Gets the &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;OrganizationRequest&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&apos;s that where sent using &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;OrganizationService&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// or &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;OrganizationServiceContext&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The sent &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;OrganizationRequest&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&apos;s.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IList&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OrganizationRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SentOrganizationRequests&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OrganizationRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Gets the organization service.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The organization service.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;seealso&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;IOrganizationService&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IOrganizationService&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Gets the typed organization service context.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The organization service context.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;seealso&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ICrmSession.OrganizationServiceContext&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Dispose&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        IOrganizationService&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SetUpOrganizationServiceFake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; result&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; A.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Fake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IOrganizationService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // Record all call OrganizationRequest&apos;s sent to .Execute() in SentOrganizationRequests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            A.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CallTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Execute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(A&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OrganizationRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;._))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ReturnsLazily&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OrganizationRequest&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                    SentOrganizationRequests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(request);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                    return&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrganizationResponse&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                        Results &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ParameterCollection&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                        ResponseName &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Guid.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NewGuid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ToString&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SetUpOrganizationServiceContextFake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; result&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; A.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Fake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;OrganizationServiceContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            A.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CallTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(result)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Where&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; call.Method.Name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;CreateQuery&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;WithNonVoidReturnType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CallsBaseMethod&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I created a little reusable base class for all my tests which sets up a new &lt;code&gt;CrmSessionFake&lt;/code&gt; for every test and disposes it on tear down of each test:&lt;/p&gt;
&lt;h3 id=&quot;crmsessiontestbase&quot;&gt;CrmSessionTestBase:&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; abstract&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionTestBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFake&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IOrganizationService&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OrgService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SetUp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SetUpCrmSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            CrmSession &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CrmSessionFake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TearDown&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; TearDownCrmSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            CrmSession&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Dispose&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            CrmSession &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally code the test for &lt;code&gt;MyService&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; NUnit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Framework&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TestFixture&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyServiceTests&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CrmSessionTestBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Test&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Test_InsertNewEntity&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // Arrange&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; service&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CrmSession);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // Act&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        service.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Serve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;John&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // Assert that a CreateRequest was set up and fired corretly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        CrmSession.SentOrganizationRequests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Should&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;HaveCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        CrmSession.SentOrganizationRequests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;First&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Should&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;BeOfType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ExecuteTransactionRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        ((&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ExecuteTransactionRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)CrmSession.SentOrganizationRequests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;First&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()).Requests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Should&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;HaveCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        ((&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ExecuteTransactionRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)CrmSession.SentOrganizationRequests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;First&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()).Requests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;First&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Should&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;BeOfType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CreateRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CreateRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)((&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ExecuteTransactionRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) CrmSession.SentOrganizationRequests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;First&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()).Requests.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;First&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; entity&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; request.Target;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        entity.Name.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Should&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Be&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;John&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Remark:&lt;/strong&gt; In practice the logic in &lt;code&gt;MyService&lt;/code&gt; is slightly more complex then in this example so testing it makes a lot more sense and there may be more then one simple test.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion:&lt;/h2&gt;
&lt;p&gt;My main point besides providing some code samples is that even with the CRM SDK one can (and should) do unit-testing for your C# code. The most important one to test in every application is the business- / domain-logic. Its where the business value comes from and makes your application worth living.&lt;/p&gt;
&lt;p&gt;You can go even further then the above samples. Some ideas (and work in progress at my company):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implement helper methods in your test baseclass to do standard test validations like the &lt;code&gt;SentOrganzationRequests&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Introduce more abstraction from the CRM SDK by wrapping the API’s you need in their own interface.&lt;/li&gt;
&lt;li&gt;When writing CRM plugins and workflow-activities extract your logic out of your plugin code. Decouple them from the SDK plugin method.&lt;/li&gt;
&lt;li&gt;In plugins and workflow activities wrap your OrgContext and Service in a &lt;code&gt;ICrmSession&lt;/code&gt; too and write your code against this interface&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just some ideas.&lt;/p&gt;
&lt;p&gt;Go and do it! Its cool coding work – way better then do manual testing all the time. Spend you time in automate things once instead in doing manual work (testing) over and over again.&lt;/p&gt;
&lt;p&gt;You are a developer – a coder – not a click-user! 🙂&lt;/p&gt;</content:encoded></item><item><title>C# Regions are Evil</title><link>https://marcduerst.com/blog/c-regions-are-evil/</link><guid isPermaLink="true">https://marcduerst.com/blog/c-regions-are-evil/</guid><description>The programming language C# supports the use of regions since ever. To be more precise it dates back into VS .Net 2003 and .Net 1.x. The concept is fairly si...</description><pubDate>Mon, 03 Oct 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The programming language C# supports the use of &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/9a1ybwek%28v=vs.71%29.aspx?f=255&amp;#x26;MSPPError=-2147217396&quot;&gt;regions&lt;/a&gt; since ever. To be more precise it dates back into VS .Net 2003 and .Net 1.x. The concept is fairly simple: use the keyword &lt;code&gt;#region&lt;/code&gt; and &lt;code&gt;#endregion&lt;/code&gt; to mark a block of code as a collapsible and optionally named region.&lt;/p&gt;
&lt;h2 id=&quot;history&quot;&gt;History&lt;/h2&gt;
&lt;p&gt;Where do the regions come from? They started with C# 1 when the language did not have that much language features. Not only Generics where missing but also partial classes didn’t exists.&lt;/p&gt;
&lt;p&gt;In these early days tools like Visual Studio did use the regions to wrap their generated code. This way the IDE by default collapsed the code generated from tools like the Forms-Designer.&lt;/p&gt;
&lt;p&gt;With C# 2.0 Microsoft introduced the feature called &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/wa80x488%28v=vs.80%29.aspx?f=255&amp;#x26;MSPPError=-2147217396&quot;&gt;partial classes&lt;/a&gt;. With this feature a class can span more then one file so the tools could generate their code into an entire separate file. No need for regions anymore.&lt;/p&gt;
&lt;p&gt;Additionally Microsoft added foldable code sections based on the semantics of the code into the text editor. This way a developer can collapse methods, IF-Statements, classes, namespaces, etc.&lt;/p&gt;
&lt;h2 id=&quot;today&quot;&gt;Today&lt;/h2&gt;
&lt;p&gt;I am surprised how many developers still use Regions in their C# code even in 2016. Some years ago I tend to use regions too. That time seniors asked me: “Why are you using regions?”. My immediate answer was to clean the code and increate its readability. Shouldn’t one structure its code the way collapsable code (aka regions) is not needed at all? From then on I challenged myself for each use of a region: “This should go into its own method (or even its own class). Should it?”. The result was, that I never ever wrote a region again.&lt;/p&gt;
&lt;h2 id=&quot;problems-with-regions&quot;&gt;Problems with regions&lt;/h2&gt;
&lt;p&gt;So what are the problems with regions? Why the hell do I write an entire blog article about them? Even in 2016 developers around the world (or at least around Europe) are still using them. This made me think about the problems with regions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Regions are painful for other developers inspecting your the first time. They first have to expand all the collapsed sections to get the full picture of the code. And because of all the &lt;code&gt;#region&lt;/code&gt;and &lt;code&gt;#endregion&lt;/code&gt; lines the code gets even larger.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Regions often lead to bad code because developers easily put a region around larger code blocks to make them hide instead of thinking how to structure their code well.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The second issue is really bad. Stuff that leads in writing bad code hurts me. Regions are one of these things.&lt;/p&gt;
&lt;p&gt;I find usages of regions mainly in these places:&lt;/p&gt;
&lt;h3 id=&quot;grouping-members-in-a-class-private-public-etc&quot;&gt;Grouping members in a class (private, public, etc.&lt;/h3&gt;
&lt;p&gt;If a class contains that many members so collapsable grouping is needed the class probably needs to be split into multiple classes. With large classes chances are hight that they are responsible for too many things. See the “Single Responsibility Principle” from &lt;a href=&quot;https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)&quot;&gt;SOLID&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On the other hand: if a class only serves a single responsibility it is probably small enough so it doesn’t need regions for grouping its members.&lt;/p&gt;
&lt;p&gt;Using regions here lead in bad design of the classes as they handle way too many things. For small classes regions are just a waste of code-lines. No need for regions here.&lt;/p&gt;
&lt;h3 id=&quot;regions-within-methods&quot;&gt;Regions within methods&lt;/h3&gt;
&lt;p&gt;That’s another area I regularly find regions. When methods get a little longer some developers tend to group the sub-parts of a method into regions. I did so too. The idea is that one can collapse them and just read the region-names to get the big picture of the method.&lt;/p&gt;
&lt;p&gt;As you may guess: bad design too. Not only clean-code suggest to write short methods so maintenance and testability of them is good.&lt;/p&gt;
&lt;p&gt;Instead of using a region here one can easily extract a new method with the given block of code. Sometimes extracting its own class is even a better match. If a developer cares about the “Single Responsibility Principle” the classes don’t get that complicated so methods tend to be less complex and shorter too.&lt;/p&gt;
&lt;p&gt;So again: using regions here leads in bad code.&lt;/p&gt;
&lt;h3 id=&quot;collapse-generated-code&quot;&gt;Collapse generated code&lt;/h3&gt;
&lt;p&gt;As written above: since C# 2.0 there are partial classes for this. Use them instead regions!&lt;/p&gt;
&lt;h2 id=&quot;what-to-do-with-regions&quot;&gt;What to do with regions&lt;/h2&gt;
&lt;p&gt;It would be great if Microsoft can remove them from the language features but this isn’t really an option as it will break a lot of existing code. So the best thing is to not use them anymore.&lt;/p&gt;
&lt;p&gt;So far so good but what with existing code?&lt;/p&gt;
&lt;p&gt;One of the first Visual Studio extensions I install on my dev machines is the &lt;a href=&quot;https://visualstudiogallery.msdn.microsoft.com/0ca60d35-1e02-43b7-bf59-ac7deb9afbca&quot;&gt;“I hate regions”&lt;/a&gt; extension. It auto-expand all regions and renders them in a small and grey font so the don’t disturb that much.&lt;/p&gt;
&lt;p&gt;Another thing one can do is to set up a R# rule and apply it to the entire solution. Bye-bye regions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So, dear developers – don’t use regions anymore. Let them go! R.I.P Regions!&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title>Quick developer journey on Microsoft Application Insights</title><link>https://marcduerst.com/blog/quick-developer-journey-on-microsoft-application-insights/</link><guid isPermaLink="true">https://marcduerst.com/blog/quick-developer-journey-on-microsoft-application-insights/</guid><description>I am currently working on a new little web application using the good old ASP.Net MVC 5. This application should be hosted on Azure App Service and as our co...</description><pubDate>Fri, 29 Jul 2016 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: appis_1.png --&gt;
&lt;!-- MISSING IMAGE: image11.png --&gt;
&lt;!-- MISSING IMAGE: image3.png --&gt;
&lt;!-- MISSING IMAGE: image4.png --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 4 images that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2016/07/appis_2.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I am currently working on a new little web application using the good old ASP.Net MVC 5. This application should be hosted on Azure App Service and as our company is highly committed to the Azure Cloud we also have all kind of subscriptions in place. When Visual Studio 2015.3 asked me whether to active the “Application Insights” I quickly decided to do so and created the Azure ResourceGroup as well as set up AppInsight as part of the “New Project” wizard of Visual Studio. I thought this way I can get familiar with AppInsights.&lt;/p&gt;
&lt;p&gt;After coding some days on the app I recognised a red square in my code today followed by the text “2 Exceptions”:&lt;/p&gt;
&lt;p&gt;“&lt;em&gt;aw&lt;/em&gt; I must click this thing!” came immediately to my mind. Did so:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://marcduerst.com/images/posts/2016/07/appis_2.png&quot; alt=&quot;appis_2&quot;&gt;&lt;/p&gt;
&lt;p&gt;Wait, what? “&lt;em&gt;2 (new)&lt;/em&gt;” … ah got it: “&lt;em&gt;2 new NotImplementedException at TfsProjectWriter.CreateProject. The method or operation is not implemented.&lt;/em&gt;“. Ok, not to surprising as I am currently in the middle of implementing this application and I ran it quite some times already on my dev machine. But App Insight seems to record these things already and there are these cute little links again one just can not resist to click.&lt;/p&gt;
&lt;p&gt;As a developer I first clicked “Go to code”. It took me directly to the code of the “CreateProject” method which shows me the problem. Same thing when clicking the blue method name itself:&lt;/p&gt;
&lt;p&gt;Ok, no surprise here and code is always good. But what where those other cute little links?&lt;/p&gt;
&lt;h2 id=&quot;view-all-exceptions-in-this-app&quot;&gt;View all exceptions in this app&lt;/h2&gt;
&lt;p&gt;This one takes you to a Visual Studio panel where you can query all reported exceptions users experienced in your application. One can sort, filter, drill-down and more – all kind of querying of exception data directly within Visual Studio. You can drill-down and get all the information about the exceptions including inner-exceptions and interactive stack-trace etc.&lt;/p&gt;
&lt;p&gt;There are tons of filter options. Not only the exception info but also which user from what location, hardware etc. The kind of information from browser HTTP requests.&lt;/p&gt;
&lt;p&gt;From the exception details one can query other exceptions wich may relate based on criteria filtering of the source exception. For example check other exceptions of this user in that timeframe or check if other users had the same issue (called “Problem”). This way you can get the context why the errors happened so you can fix it easily.&lt;br&gt;
Nice but what is the Trend thing. Sound promising too.&lt;/p&gt;
&lt;h2 id=&quot;trends&quot;&gt;Trends&lt;/h2&gt;
&lt;p&gt;The trends links open another Visual Studio panel which shows kind of a multidimensional cube with all possible data about request, responses, errors, performance, etc. One can again filter, group, sort, visualise them in many possible ways – just as you would except from a cube. All straight within Visual Studio just two clicks away from your actual code! The following screenshot show some of the options.&lt;/p&gt;
&lt;p&gt;You can query all possible things – again using request and application data. You have a ton of options. To make the start with that Cube a little easier there are pre-build queries one can click and get the cube pre-configured:&lt;/p&gt;
&lt;h2 id=&quot;azure-portal-integration&quot;&gt;Azure Portal Integration&lt;/h2&gt;
&lt;p&gt;The Application Insights are nicely integrated into the Azure Portal. So one can query things from outside of Visual Studio within any web-browser:&lt;/p&gt;
&lt;h2 id=&quot;application-insights-portal&quot;&gt;Application Insights Portal&lt;/h2&gt;
&lt;p&gt;If you are a real hardcore analytic you may like to get even more query options. So you can point your web-browser to the Application Insight Portal and get the full blown thing. Here you can even write your own queries:&lt;/p&gt;
&lt;p&gt;And did you hardcore analytics see the ultimate hard-core option: “&lt;em&gt;Export to PowerBI&lt;/em&gt;“. Have fun!&lt;/p&gt;
&lt;h2 id=&quot;downside-of-application-insight&quot;&gt;Downside of Application Insight&lt;/h2&gt;
&lt;p&gt;Yes, there is a downside. More exactly there are two downsides:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There is no on-prem version – it’s cloud-only.&lt;/li&gt;
&lt;li&gt;At the time writing this Application Insight Data can only be hosted in the U.S. No option to host it at least on continental europa.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This means you need to closely consider privacy for each of you apps, project and customer. For me these two options are a no-go for at least half of the projects/customers.&lt;/p&gt;
&lt;h2 id=&quot;integration-options-for-your-app&quot;&gt;Integration options for your App&lt;/h2&gt;
&lt;p&gt;You can integration the collecting of Application Insight data in more then one way.&lt;/p&gt;
&lt;p&gt;Every web-application can include a Application Insight Javascript and collect data via browsers. As this is a simple option and open for all kind of web-apps it can not collect server-inside data.&lt;/p&gt;
&lt;p&gt;For this you can use the Application Insight SDK on the server and log your stuff. If you are a ASP.Net developer Microsoft has the option already in the stack and you just have to activate it. If you like to get more then the default data you can add SDK-Calls to your server-code too. Same for the client-code using their Javascript-SDK.&lt;/p&gt;
&lt;p&gt;So far I didn’t explore the options for native-, desktop- and mobile-apps but I am pretty sure one can use the SDK and fire the log-requests from those platforms too.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Besides the obvious pros and cons it’s the first time I can watch my code to be alive when users are actively using it. Especially with the “Live” views it’s like you see your users using your software. It’s kind of feeling you software. Cool stuff. But there is the privacy side too. Sure it’s anonymized but somehow – especially the live-viewing – feels a little bit wrong to my Swiss culture. Maybe I just have to get used to it.&lt;/p&gt;
&lt;p&gt;But all in all its cool tech and I like to explore it more when real usage data will come in.&lt;/p&gt;</content:encoded></item><item><title>Git Pull Requests and Reviews in TFS/VSTS</title><link>https://marcduerst.com/blog/git-pull-requests-and-reviews-in-tfsvsts/</link><guid isPermaLink="true">https://marcduerst.com/blog/git-pull-requests-and-reviews-in-tfsvsts/</guid><description>TFS or its cloud instance Visual Studio Team Services (VSTS) does have a very nice integration of GIT as a distributed version control system (DVCS). This is...</description><pubDate>Fri, 22 Jul 2016 00:00:00 GMT</pubDate><content:encoded>&lt;!-- MISSING IMAGE: 1_create_git_repo.png --&gt;
&lt;!-- MISSING IMAGE: 10_exceptions.png --&gt;
&lt;!-- MISSING IMAGE: 2_open_branch_policies1.png --&gt;
&lt;!-- MISSING IMAGE: 3_branch_policies.png --&gt;
&lt;!-- MISSING IMAGE: 4_change_in_featurebranch.png --&gt;
&lt;!-- MISSING IMAGE: 5_new_pull_request.png --&gt;
&lt;!-- MISSING IMAGE: 6_list_pr.png --&gt;
&lt;!-- MISSING IMAGE: 7_details_pr.png --&gt;
&lt;!-- MISSING IMAGE: 7_leave_comment1.gif --&gt;
&lt;!-- MISSING IMAGE: 8_complete_pull_request.png --&gt;
&lt;!-- MISSING IMAGE: 9_complete_pull_request_window.png --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally contained 11 images that could not be recovered during the WordPress migration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;git-pull-requests-and-reviews-intfsvsts&quot;&gt;GIT Pull-Requests and Reviews in TFS/VSTS&lt;/h1&gt;
&lt;p&gt;TFS or its cloud instance Visual Studio Team Services (VSTS) does have a very nice integration of GIT as a distributed version control system (DVCS). This is build into TFS since TFS 2015 and did extend with every release of TFS. The TFS Version Control backend (TFVC) is still available but my first choice when I create a new source-code repository is GIT.&lt;/p&gt;
&lt;h2 id=&quot;how-to-create-a-git-repo-in-tfs&quot;&gt;How to create a GIT repo in TFS&lt;/h2&gt;
&lt;p&gt;This is a snap. Just go to your TFS / VSTS &lt;em&gt;Team Project&lt;/em&gt; open its settings page using the gear icon in the upper left corner.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Tab “Version Control”.&lt;/li&gt;
&lt;li&gt;Press “New pository…”&lt;/li&gt;
&lt;li&gt;Choose  the “Type”. Default is already GIT.&lt;/li&gt;
&lt;li&gt;Give it a name and hit “Create”.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Each &lt;em&gt;Team Project&lt;/em&gt; can have only one TFVC repository but an unlimited number of GIT repositories. One of the advantages when using GIT repos.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;set-up-your-branches-for-pull-requests&quot;&gt;Set up your branches for pull-requests?&lt;/h2&gt;
&lt;p&gt;Go again to the V_ersion Control_ settings of your &lt;em&gt;Team Project&lt;/em&gt; and choose the branch you like to configure and switch to its Branch Policies:&lt;/p&gt;
&lt;p&gt;Here you can configure the branch as you like. Check out the zoom-in of the options – quite impressive I would say but wait until you see them in action:&lt;/p&gt;
&lt;p&gt;First you can force pull-requests to the given branch and specify a build job that gets triggered as the developer sends in a pull-request. You can configure how often the build job runs and if the pull-request gets blocked if the build job is not yet run successfully. I prefer to block it so I force everybody in the project to have builds running which includes unit-tests must passing.&lt;/p&gt;
&lt;p&gt;Then you can configure if the pull-request must be linked with work items and if it should be blocked or not. I normally don’t block them as this gets hard for checking in fixes etc. But I active it so I will get an indicator showing me if the pull-request is linked or not. As a lead-dev I then can consider contacting the team member to ask for work items.&lt;/p&gt;
&lt;p&gt;A really cool thing are the review options. Configuration is pretty self explaining. You’ll see it in action later on.&lt;/p&gt;
&lt;p&gt;Finally you can configure who of your team members can or must review what part (path) of your repository. So if someone for example checks in code in a core library path maybe the lead-dev for the library should review that change too.&lt;/p&gt;
&lt;h2 id=&quot;now-what&quot;&gt;Now what?&lt;/h2&gt;
&lt;p&gt;With the above settings in place your team-members can not push changes directly to the &lt;em&gt;master&lt;/em&gt; branch anymore. If they try they will get an error. Instead they have to create feature branches, push them and when done with the feature send a pull-request for this feature branch. Think of it as a “request to pull the changes from the feature branch to the target branch” (normally into the &lt;em&gt;master&lt;/em&gt; branch). The lead-dev (or who ever is in charge) can check this pull-request and decide if he likes to integrate it the master branch.&lt;/p&gt;
&lt;h2 id=&quot;create-a-pull-request&quot;&gt;Create a pull-request&lt;/h2&gt;
&lt;p&gt;For the demo I’ve created a little change in feature branch &lt;em&gt;feature/blog_test&lt;/em&gt; and pushed it to the GIT server (aka GIT remote). As you see TFS will just prompt me to create a pull-request for it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you edit a file directly in the TFS web UI and try to push it to the master branch TFS will prompt you to right away create a feature branch for you and push it include creating a pull-request. Cool!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I can eighter continue work on the feature and push more commits to it or I can create a pull-request now.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You can create the feature branch our own using the GIT client of your choice or you can use the TFS web-ui to do it. For example you can create a feature branch directly from within your product backlog item / user story. This will link the feature-branch automatically with your work-item. The feature branch can also be created from the &lt;em&gt;Code&lt;/em&gt; page. Many options to do it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So let’s create a pull-request now by clicking the &lt;em&gt;New pull request&lt;/em&gt; button in the TFS web-ui.&lt;/p&gt;
&lt;p&gt;Here you can check and complete the information about this pull-request. You may wanna update the description and link it with work item(s). You also can specify the reviewers you like to get reviews from (or leave the defaults in place).&lt;/p&gt;
&lt;p&gt;Click &lt;em&gt;New pull request&lt;/em&gt; and the pull-request will be sent to the team and reviewers. Your job as Dev for this feature is done now. Except: you like to get the review’s done so your feature gets the DoD (&lt;em&gt;Definition of Done&lt;/em&gt;) pass.&lt;/p&gt;
&lt;h2 id=&quot;how-to-integrate-the-pull-requests&quot;&gt;How to integrate the pull-requests?&lt;/h2&gt;
&lt;p&gt;So, what do have so far after the developer created the new pull-request you may ask? We still have the developers feature branch and we have a pull-request which requests to integrate this feature branch into the master branch (or how else you called your branch). TFS also fired the build job specified in the branch policies on the feature branch. The reviewer got notified that there is a pull-request ready for review. So far nothing changed on the master branch – that’s important.&lt;/p&gt;
&lt;p&gt;Now, when you (the Lead Dev, Reviewer or Team-Member with appropriate permissions) go to the &lt;em&gt;Code &gt; Pull Requests&lt;/em&gt; you’ll see the pending pull-requests.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; On the top you have filters like &lt;em&gt;Mine&lt;/em&gt;, &lt;em&gt;Active&lt;/em&gt;, &lt;em&gt;Completed&lt;/em&gt; and &lt;em&gt;Abandoned&lt;/em&gt;. It took me a while to find them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When you click on a pending pull-request you’ll get the details for this request:&lt;/p&gt;
&lt;p&gt;I like that UI but its not obvious how it work when you see it the first time. So I highlighted some interesting stuff.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the middle column you see the pull-request header (from/to branch etc). Just below you again get filters / tab-pages. By default the &lt;em&gt;Discussion&lt;/em&gt; tab is active but you can switch to &lt;em&gt;File&lt;/em&gt; and &lt;em&gt;Commit&lt;/em&gt; to check those  details too.&lt;/li&gt;
&lt;li&gt;On the top right you’ll see a list of indicators depending on your branch policies. Things like if merge-conflicts would happen, review-status, work-item assignements  and – if configured – the build-status. Below there are the two possible actions: &lt;em&gt;Complete pull-request&lt;/em&gt; and &lt;em&gt;Abandon&lt;/em&gt;. We’ll get to this in second.&lt;/li&gt;
&lt;li&gt;Further more on the right side you have the &lt;em&gt;Review&lt;/em&gt; area. You see who reviewed with what feedback and you can give your own feedback. You also can leave comments in the Discuss area in the middle and even cooler you can leave your review-comment directly in the source-code view on per line base:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, if everything is OK with the pull-request you can &lt;em&gt;Complete pull request&lt;/em&gt; using the button on the top left.&lt;/p&gt;
&lt;p&gt;You’ll then get asked for some details:&lt;/p&gt;
&lt;p&gt;Here you can finally fix up subject and description and have to nice GIT shortcuts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Delete after merge&lt;/em&gt; will delete the feature branch after it was successfully merged into the target branch (here &lt;em&gt;master&lt;/em&gt;). Folks pulling/syncing will get it deleted too but in case there tracking the branch locally they have to delete their local branch manually. But at least they see that it is gone on the remote server already. Nice timesaver.&lt;/li&gt;
&lt;li&gt;Squash changes uses the GIT “Squash” feature to compact the history. All the commits in the feature branch will be packed into one single commit in the &lt;em&gt;master&lt;/em&gt; branch. So we “squash” all commit together to be one single commit in the history of the &lt;em&gt;master&lt;/em&gt; branch. It’s a matter of taste how you like to have your history look like. Again: nice timesaver.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now the final act is to press the &lt;em&gt;Complete merge&lt;/em&gt; button. The TFS server will fire all the GIT commands to integrate it into the &lt;em&gt;master&lt;/em&gt; branch and – if checked – delete the feature branch. If you have continuous integration build-jobs and even continuous deployment release-jobs active the will be fired right now on the &lt;em&gt;master&lt;/em&gt; branch – just as you they would when committing normally to the &lt;em&gt;master&lt;/em&gt; branch.&lt;/p&gt;
&lt;h2 id=&quot;need-a-backdoor&quot;&gt;Need a backdoor?&lt;/h2&gt;
&lt;p&gt;For a lead-dev it may be a good option to provide a backdoor around all the pull-request, review blocking for the case of an emergency. For example during a release you need to adjust something (aka quick-fix while releasing). I know, this will never happen! …but well …  yea – somehow those situations di happen – maybe it’s just me 😉&lt;/p&gt;
&lt;p&gt;I found that on branch settings one can give right to &lt;em&gt;Exempt from policy enforcement&lt;/em&gt;. That’s you backdoor.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I really like what TFS/VSTS has to offer on its GIT integration and how it all plays nicely with work planning, build- and release jobs. With the latest version this stuff is all available directly in the web UI so you don’t need Visual Studio anymore to control TFS. You can use any IDE/TextEditor and the GIT client of your choice. The rest can be done using the web UI. If you did not look at TFS for some time you might wanna give it a try again.&lt;/p&gt;
&lt;p&gt;You can create yourself a developer account on Azure and get free VSTS (TFS online) as well as 10 free web apps and more.&lt;/p&gt;
&lt;p&gt;Let me know what you think of this stuff.&lt;/p&gt;</content:encoded></item><item><title>How to start Unit Testing</title><link>https://marcduerst.com/blog/how-to-start-unit-testing/</link><guid isPermaLink="true">https://marcduerst.com/blog/how-to-start-unit-testing/</guid><description>So here I put some thoughts and tips how to start more easily with unit-testing. Hopefully I can tear down some walls.</description><pubDate>Mon, 18 Jul 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So here I put some thoughts and tips how to start more easily with unit-testing. Hopefully I can tear down some walls.&lt;/p&gt;
&lt;p&gt;I don’t extend to much on the &lt;em&gt;why&lt;/em&gt; as &lt;a href=&quot;http://stackoverflow.com/questions/67299/is-unit-testing-worth-the-effort&quot;&gt;many others&lt;/a&gt; have written about it already. Just my personal motivation to write unit-tests:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Besides all the more official pros the one matters for me is that I can sleep better – especially before and after releases – when I know my test-suites are green. I know &lt;em&gt;“hey, the basics are working and I did not break things I once tested. So if something arise it’s probably a border-case issue or at least something within the new stuff so its not high-priority.”.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Second I like to do a good job in design and programming software. Unit-Tests allows me to kind of ensure this the way I can write the tests for the functionality I expect and validate it now and for all times.&lt;/li&gt;
&lt;li&gt;Finally I am a developer! I like to spent my time way more on writing code then do stupid repetitively manual testing. Automating things is deep in a Dev’s DNA and that’s a good thing. Write a script/code once – use it many times. That’s how Developers to it! We have to power to do magic things that other can’t do. Its awesome to be Dev – use your power!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;dont-have-time-to-test-all&quot;&gt;Don’t have time to test all?&lt;/h2&gt;
&lt;p&gt;Easy! I don’t have it either – at least not always. You can start with the most important parts. You will never ever have 100% code coverage. Even 80-90% is hard. And who cares about those values anyway! Don’t get me wrong – I like to run code-coverage from time to time to see what parts of the code are lacking unit-test. But the fixed percentage number can lead to write strange unit-tests just to get another percent code-coverage.&lt;/p&gt;
&lt;h2 id=&quot;start-small&quot;&gt;Start small&lt;/h2&gt;
&lt;p&gt;Give yourself success and start small. When writing your next peace of code think about it: “What is the core logic of this? Let’s write a small unit-tests which ensures this basic functionality.”. Start using baby-steps will give you success experience which is very important to not end frustrated and throw it away again.&lt;/p&gt;
&lt;p&gt;You probably will find code you need to refactor to test it. Even after years of unit-testing I find myself refactoring code because of writing the unit-tests showed it is not nicely organized (eg. separated). So writing unit-tests leads to writing better productive code. That’s a real good side-effect of unit-testing / test-automation.&lt;/p&gt;
&lt;h2 id=&quot;what-should-i-test-first&quot;&gt;What should I test first?&lt;/h2&gt;
&lt;p&gt;So where to start with unit-testing? Where should I spend my time first regarding writing automated unit-test? Here is my priority list:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Test core functionality first. For me this normally is the domain-logic / business-logic. This is the hart of the app. Its the part that brings in the real value. If nothing else is validated but this part of your app should be.&lt;/li&gt;
&lt;li&gt;Regression bugs: If a bug will be re-introduced in a later release again even if it was fixed already, its called a “regression bug”. These should never happen. It makes customers really unhappy. So if I fix a bug I try to write a unit-test for it do be sure this bug will never ever make its way into a future release.&lt;/li&gt;
&lt;li&gt;Extend automated tests as needed and as you can make time available for it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Important: do start write unit-tests where it make the most sense and adds the most value! They don’t have to be perfect. They don’t need to shine.&lt;/p&gt;
&lt;h2 id=&quot;how-can-i-reduce-the-time-it-needs-to-write-unit-test&quot;&gt;How can I reduce the time it needs to write unit-test?&lt;/h2&gt;
&lt;p&gt;First, it needs practice. You will learn what make testing easier and what doesn’t. Let me introduce you my time-savers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write clean-code using &lt;a href=&quot;https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)&quot;&gt;SOLID principals&lt;/a&gt; – especially useful for writing unit-tests is the “&lt;a href=&quot;https://en.wikipedia.org/wiki/Single_responsibility_principle&quot;&gt;Single Responsibility&lt;/a&gt;” principal. This basically means that one class should have only one job. Keep classes small und tire them to a single purpose. This results in clean, maintainable and extensible code and also make unit-testing for those classes a lot easier. Together with “&lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_inversion_principle&quot;&gt;Dependency inversion&lt;/a&gt;” principle (DI) this is a real enabler as you don’t need to mock/fake the whole universe.&lt;/li&gt;
&lt;li&gt;Don’t forget about your developer skills when writing unit-tests! Use language features like OOP, inheritance, extension methods and handy patterns. You can make base-classes and reusable helper. Cool coding stuff! Don’t do stupid copy-paste just because these are unit-tests. Use you engineering power and write clean code in unit-tests. They get more maintainable and it makes a lot more fun to write unit-tests.&lt;/li&gt;
&lt;li&gt;Don’t do automated UI testing until you really, really, really need it. This needs a lot of time and they normally tend to need a lot of maintenance time. Instead use patterns like MVVM and *only* test your view-model logic.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;example&quot;&gt;Example:&lt;/h4&gt;
&lt;p&gt;Let’s image you are writing some migration software which reads from one datasource, transform the data and write it to another datasource.&lt;/p&gt;
&lt;p&gt;Instead of writing one class that read, transform and write you should have written tree classes regarding &lt;em&gt;single responsibility&lt;/em&gt;: one for reading, one for transforming and one for writing.&lt;/p&gt;
&lt;p&gt;You application can chain these classes together using interfaces for them as promoted by &lt;em&gt;dependency inversion&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Now you have tree classes and three interfaces. What do you think will be the most important part to write unit-tests for? Right: the transformation. This is why your app exists at all so make sure this central component works. Its easy as you have interfaces for reading and writing. You can mock or fake them easily and have tests ready.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IMyReader&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    IEnumerable&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Read&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IMyWriter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Write(string data);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IMyTransformer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Transform&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyTransformer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IMyTransformer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyTransformer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IMyReader&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; reader&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IMyWriter&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; writer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Transform&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; line&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; reader.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Read&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // DO TRANSFORM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            writer.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(line);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the unit-tests for &lt;code&gt;MyTransformer&lt;/code&gt; can be as easy as follows:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; reader&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; A.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Fake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;reader.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CallTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Read&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Returns&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;test input string&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; writer&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; A.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Fake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;reader.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CallTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Write&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MustHaveHappened&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; transformer&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Transformer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(reader, writer);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;transformer.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Transform&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// TODO: Additional test of the transformation result&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: The above code use my famous mock/fake-library “&lt;a href=&quot;http://fakeiteasy.readthedocs.io/en/stable/quickstart/&quot;&gt;Fake it easy&lt;/a&gt;” (best-of Moq and Rhino Mocks).&lt;/p&gt;
&lt;h2 id=&quot;libraries&quot;&gt;Libraries&lt;/h2&gt;
&lt;p&gt;To get you started writing unit-tests for your C# code here the libraries / tools I use for most of my testing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.nunit.org&quot;&gt;NUnit&lt;/a&gt; – Unit-Testing framework&lt;/li&gt;
&lt;li&gt;NUnit Test Adapter – Allows running NUnit tests on VSTS/TFS and within Visual Studio Test-Runner&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Visual_Studio_Unit_Testing_Framework&quot;&gt;MSTest&lt;/a&gt; – Unit-Testing framework from Microsoft&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fakeiteasy.github.io&quot;&gt;Fake it easy&lt;/a&gt; – Mock and Fake library to setup fake implementations in no time&lt;/li&gt;
&lt;li&gt;[FluentAssertion](&lt;a href=&quot;http://fluent&quot;&gt;http://fluent&lt;/a&gt; assertion) – Let’s one write the assertions with a nice and fluent syntax&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jetbrains.com/resharper/features/unit_testing.html&quot;&gt;R# Testrunner&lt;/a&gt; – To run tests during development&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Now go and write unit-tests!&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title>Decouple IoC/DI container when authoring a C# library</title><link>https://marcduerst.com/blog/decouple-iocdi-container-when-authoring-a-c-library/</link><guid isPermaLink="true">https://marcduerst.com/blog/decouple-iocdi-container-when-authoring-a-c-library/</guid><description>Often when writing library code the integration of an IoC/DI container (eg. Unity, SimpleInjector, etc.) gets a topic. My goals are to use Inversion Of Contr...</description><pubDate>Sat, 16 Jul 2016 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;decouple-iocdi-container-when-authoring-a-clibrary&quot;&gt;Decouple IoC/DI container when authoring a C# library&lt;/h1&gt;
&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;
&lt;p&gt;Often when writing library code the integration of an IoC/DI container (eg. Unity, SimpleInjector, etc.) gets a topic. My goals are to use Inversion Of Control (IoC) and dependency injection (DI) to decouple things but don’t force the application to use one or another specific container. The user of my libraries should be free in choosing its IoC/DI container. On the other hand I like to give the users of my library a easy way to register the defaults types – again – without forcing one or another IoC/DI container product.&lt;/p&gt;
&lt;p&gt;I noticed how ASP.Net core does their DI: they ship their own IoC/DI with the option to replace it with the one of your choice. For my &lt;em&gt;little libraries&lt;/em&gt; this feels like an overkill. Even if writing a IoC/DI would be a nice and cool programming task 😉&lt;/p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;/h2&gt;
&lt;p&gt;So I decided to do it way simpler by introducing a interface for register types with &lt;em&gt;any&lt;/em&gt; IoC/DI container. I normally don’t use the Service-Locator pattern in my source-codes but there are very rare situations where it gets hard without it. So I also added an minimalistic interface for service location.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IServiceContainer:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It features three methods for register types with the DI container: &lt;code&gt;RegisterTransient()&lt;/code&gt;, &lt;code&gt;RegisterSingleton()&lt;/code&gt; and &lt;code&gt;RegisterInstance()&lt;/code&gt;. See code and doc below for more details.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// Specify the API of a basic Service Container implementation.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;remarks&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// All RegisterType-Calls should be implemented against this interface so the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// final DI/IoC-Container can be freely choosen if there is a IServiceContainer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// implementation for it. If not one can easely write its own.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;remarks&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IServiceContainer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Registers the type &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparamref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;TFrom&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; to be implemented&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// by type &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparamref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;TTo&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; with an optional &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;paramref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;factory&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// TRANSIENT: Each time the type is resolved it will create a new instance.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparam&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;TFrom&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The type of from.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparam&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparam&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;TTo&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The type of to.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparam&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;param&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;factory&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The optional factory expression.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;param&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RegisterTransient&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Func&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;factory&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; TTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Registers the type &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparamref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;TFrom&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; to be implemented&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// by type &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparamref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;TTo&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; with an optional &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;paramref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;factory&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Singleton: A new instance is created once and then used as a Singleton.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparam&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;TFrom&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The type of from.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparam&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparam&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;TTo&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The type of to.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparam&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;param&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;factory&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The optional factory expression.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;param&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RegisterSingleton&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Func&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;factory&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; TTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Registers the type &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparamref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;TFrom&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; to be implemented&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// by type &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparamref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;TTo&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; with a pre-instantiated &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;paramref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;instance&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Instance: The given &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;paramref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;instance&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; will be used. No new instance is created.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;remarks&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Some containers refer this as &quot;external&quot;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;remarks&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparam&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;TFrom&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The type of from.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparam&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;param&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;instance&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The pre-created instance to use when an instance of &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparamref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;TFrom&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; is requested.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;param&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RegisterInstance&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; instance&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;IServiceLocator:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As mentioned I try not do use the service-locator pattern (&lt;a href=&quot;http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/&quot;&gt;why?&lt;/a&gt;) but rarely I have to. So I added the &lt;code&gt;IServiceLocator&lt;/code&gt;interface with the methods &lt;code&gt;Resolve()&lt;/code&gt;and &lt;code&gt;ResolveAll()&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// Interface for locating/resolving services/types.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;remarks&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;Use this service locator pattern with care. Use constructor parameters instead&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// whereever possible!&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;remarks&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IServiceLocator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Resolves a single instance of &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparamref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;T&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparam&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;T&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The Type one needs a instance of.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparam&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;returns&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;A single instance of &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparamref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;T&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;returns&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        T&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Resolve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Resolves all instances ot &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparamref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;T&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparam&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;T&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The Type of the instances to resolve.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparam&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;returns&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;All instances ot &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;typeparamref&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;T&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;returns&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        IEnumerable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ResolveAll&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You now may ask &lt;em&gt;“Who does the real work?”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I have an assembly / NuGet package for the concrete implementation of the above interfaces using &lt;a href=&quot;https://github.com/unitycontainer/unity&quot;&gt;Microsoft Unity&lt;/a&gt; Version 4. Its basically an adapter that routes the interface to the corresponding Unity API:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// Implements &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;IServiceContainer&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; and &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;seealso&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;IServiceLocator&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt; using Microsoft Unity. Use this&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// class if you like to get the isolutions.Library default registreions to&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// register with a Unity Container.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;seealso&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;IServiceContainer&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;seealso&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;IUnityContainer&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; UnityServiceContainer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IServiceContainer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IServiceLocator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IUnityContainer&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; container&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// Initializes a new instance of the &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;see&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cref&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;UnityServiceContainer&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; /&gt; class.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;summary&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;param&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;The optional Unity container.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;param&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; UnityServiceContainer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IUnityContainer&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; container&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.container &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; container &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; UnityContainer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // Register Unity-Implementation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            RegisterSingleton&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IServiceLocator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;UnityServiceContainer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;inheritDoc&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RegisterTransient&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Func&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;factory&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; TTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            CheckContainer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (factory &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RegisterType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RegisterType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; InjectionFactory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; factory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;inheritDoc&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RegisterSingleton&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Func&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;factory&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; TTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            CheckContainer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (factory &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RegisterType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ContainerControlledLifetimeManager&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RegisterType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                    new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ContainerControlledLifetimeManager&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                    new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; InjectionFactory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; factory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;inheritDoc&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RegisterInstance&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; instance&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            CheckContainer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RegisterInstance&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TFrom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), instance);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;inheritDoc&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; T&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Resolve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            CheckContainer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Resolve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        /// &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;inheritDoc&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IEnumerable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ResolveAll&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            CheckContainer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ResolveAll&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CheckContainer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (container &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; InvalidOperationException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;UnityServiceContainer: No container instance configured!&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Usages:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With these interfaces in place the core- as well as my other libraries can give the application service registration helpers like this one:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ServiceRegistration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; UseCore&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IServiceContainer&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; container&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (container &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;nameof&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(container));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RegisterTransient&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ISecurityHelper&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SecurityHelper&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RegisterTransient&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;IUserService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;UserService&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The application can build up the container instance during startup with code like this very easily and request the libraries to add their default service registrations:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; result&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; UnityServiceContainer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;result.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;UseCore&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;result.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;UseCoreEF6&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SampleContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;result.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;UseSampleCore&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;My core library defines the dependency injection interfaces and all other libraries use only these two interfaces. This means they all are independent from what IoC/DI container is used by the application as long as they get an implementation of these two interfaces.&lt;/p&gt;
&lt;p&gt;The Unity implementation is included in the app with a simple NuGet package the app can install. So the app can use my libraries and then decide which of my DI NuGet packages to install. One even can change the DI later on as needed. For example when moving from the full .Net framework to the .Net Core (more on this later).&lt;/p&gt;
&lt;p&gt;It’s simple, small and elegant – AND: I didn’t implement my own IoC/DI 🙂&lt;/p&gt;</content:encoded></item><item><title>Restructuring of my personal websites and blogs</title><link>https://marcduerst.com/blog/restructuring-of-my-personal-websites-and-blogs/</link><guid isPermaLink="true">https://marcduerst.com/blog/restructuring-of-my-personal-websites-and-blogs/</guid><description>After some years with the old websites and blogs several issues arised. For my personal content I had basically two sites:</description><pubDate>Fri, 15 Jul 2016 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;restructuring-of-my-personal-websites-andblogs&quot;&gt;Restructuring of my personal websites and blogs&lt;/h1&gt;
&lt;p&gt;After some years with the old websites and blogs several issues arised. For my personal content I had basically two sites:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;idev.ch&lt;/strong&gt; – Hosted my old tech blog as well as some aged software I wrote many years ago.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;marcduerst.com&lt;/strong&gt; – Site hosts my diving- and photoblog.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They both where built using Drupal 7 and hosted on a local hoster.&lt;/p&gt;
&lt;p&gt;The issues I had with them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Security updates of Drupal and – even worst – ever plugin I used to build the sites. I could have installed security updates nearly every week if I wish.&lt;/li&gt;
&lt;li&gt;idev.ch isn’t really the name I like to promote my tech blogs. It’s the label the existing users of the old software now.&lt;/li&gt;
&lt;li&gt;I like to start over again with my personal tech blog and hopefully keep the drive longer then before and update it more regularly.&lt;/li&gt;
&lt;li&gt;Adding posts to the tech blog was way to complicate. I like to spend time on the content; not the the tech behind the blog.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other goals and requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Minimize time spent on technical blog-maintenance but don’t get lazy on security.&lt;/li&gt;
&lt;li&gt;Keep tech blog separated from my dive &amp;#x26; photo blog.&lt;/li&gt;
&lt;li&gt;Keep up to date with state of the art blogging features. Eg. syndicate, share, monitor/stats, editing&lt;/li&gt;
&lt;li&gt;Use a abstract syntax to write technical blog-posts. Markdown would be nice.&lt;/li&gt;
&lt;li&gt;Have syntax-highlighting for code-blocks and inline-code.&lt;/li&gt;
&lt;li&gt;Use the domain marcduerst.com for my primary personal stuff.&lt;/li&gt;
&lt;li&gt;Keep the domain idev.ch for the old software.&lt;/li&gt;
&lt;li&gt;Increase priority of tech topics over the dive &amp;#x26; photo topics.&lt;/li&gt;
&lt;li&gt;Keep dive &amp;#x26; photo blog and also update it the future.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;platform-evaluation&quot;&gt;Platform evaluation&lt;/h2&gt;
&lt;p&gt;The main alternatives I came up regarding the tech blog platform where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install a software with easier/automated maintanance then my custom Drupal and host the site on my local hoster.&lt;/li&gt;
&lt;li&gt;Write my own blog software as an exercise for the new ASP.Net Core platform and Azure Websites.&lt;/li&gt;
&lt;li&gt;Use &lt;a href=&quot;https://jekyllrb.com&quot;&gt;Jekyll&lt;/a&gt; software to generate static website based on a GIT repository and it on local hoster or on GitHub pages.&lt;/li&gt;
&lt;li&gt;Use a cloud hosted SaaS like wordpress.com.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each has its pros and cons.&lt;/p&gt;
&lt;p&gt;Install a better updateable software may be a minor improvement and needs time to learn and build it.&lt;/p&gt;
&lt;p&gt;Write my own needs a lot of time and blogs are not the best learning example anyway. Furthermore I have to implement all current and upcoming features myself so I again spend a lot of time for tech instead content.&lt;/p&gt;
&lt;p&gt;Jekyll static site generator based on GitHub is geeky but also has quite a learning curve and needs time to build. New blog features in the future may be built myself.&lt;/p&gt;
&lt;p&gt;SaaS (WordPress.com etc) limit to what that platform actually can.&lt;/p&gt;
&lt;h2 id=&quot;decision&quot;&gt;Decision&lt;/h2&gt;
&lt;p&gt;After I tried all of them I decided go with SaaS as I am set up quickly and has a good and up-to-date featureset for blogging. Furthermore I most not spend any time over the next years to keep the platform running.&lt;/p&gt;
&lt;h2 id=&quot;action-plan&quot;&gt;Action plan&lt;/h2&gt;
&lt;p&gt;Based on the above decision and requirements I came up with the following action plan.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set up a WordPress.com blog =&gt; done&lt;/li&gt;
&lt;li&gt;Move the existing content from marcduerst.con over to tauchfotos.ch =&gt; done&lt;/li&gt;
&lt;li&gt;Point marcduerst.com to the new WordPress blog =&gt; done&lt;/li&gt;
&lt;li&gt;Rebuild idev.ch as a static HTML page just used for the old software I wrote&lt;/li&gt;
&lt;li&gt;Maybe set up an additional WordPress blog for the dive &amp;#x26; photo content over at tauchfotos.ch. Not yet sure about this.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you see my action plan makes pretty good progress but there is still work left.&lt;/p&gt;</content:encoded></item><item><title>Build a SignalR connection indicator with TypeScript and Knockout</title><link>https://marcduerst.com/blog/build-a-signalr-connection-indicator-with-typescript-and-knockout/</link><guid isPermaLink="true">https://marcduerst.com/blog/build-a-signalr-connection-indicator-with-typescript-and-knockout/</guid><description>I’ve build a message infrastructure for the company I am working for which allow to collect tons of production data from our factory (about &gt;4’000 db records...</description><pubDate>Tue, 24 Nov 2015 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;build-a-signalr-connection-indicator-with-typescript-andknockout&quot;&gt;Build a SignalR Connection Indicator with TypeScript and Knockout&lt;/h1&gt;
&lt;p&gt;I’ve build a message infrastructure for the company I am working for which allow to collect tons of production data from our factory (about &gt;4’000 db records per minute). In addition I’ve built a web frontend to query this data and to live monitor some of the data. The monitoring includes pushing current server throughput statistic data and event messages like error etc. that that happens in the factory next door including lots of additional data to understand what’s behind these errors.&lt;/p&gt;
&lt;p&gt;For this monitoring UI I used TypeScript for most of the Javascript part and SignalR to push the data from the server to the web-client. If no new problems (aka errors, warnings etc.) are shown the question was: “Is SignalR just disconnected or are we at the lucky side of the day and don’t have new problems happening in our old software?”. So I decided to implement a little indicator showing the SignalR connection status. As I googled around a little and mixed/tuned/changed existing solutions I thought it would be nice to write down how I did it for later records.&lt;/p&gt;
&lt;p&gt;First lets start up with the tech stack I used: ASP.Net MVC 5 w. Razor, TypeScript 1.6, SignalR 2.2.0, Knockout 3.3 and Bootstrap 3.3.5 are the relevant parts here.&lt;/p&gt;
&lt;h2 id=&quot;razor-view&quot;&gt;Razor View&lt;/h2&gt;
&lt;p&gt;I’ve build the following HTML (Razor but doesn’t matter here) view that holds the Bootstrap markup for the four connections states.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;connectionStateContainer&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;hidden&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;Status:&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;label label-info&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;Connecting&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;label label-success&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;Connected&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;label label-warning&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;Reconnecting&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;label label-danger&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;Disconnected&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you see I used &lt;a href=&quot;http://getbootstrap.com/components/#labels&quot;&gt;Bootstrap Labels&lt;/a&gt; for visualizing the different connection states. Further more I added &lt;code&gt;data-bind&lt;/code&gt; attributes that allow Knockout to bind the &lt;code&gt;visible&lt;/code&gt; attribute of the labels to the &lt;code&gt;connectionState&lt;/code&gt; observable properties on my view-model. The values &lt;code&gt;$.signalR.connectionState.*&lt;/code&gt; are from the SingalR Javascript library. The sourrounding DIV &lt;code&gt;#connectionStateContainer&lt;/code&gt; has the Bootstrap class ‘hidden’ so it is initially hidden until the view-model is correctly bound. Otherwise I would see all the label for a short time on screen before there are bound and therefore hidden.&lt;/p&gt;
&lt;h2 id=&quot;javascript-code&quot;&gt;Javascript Code&lt;/h2&gt;
&lt;p&gt;I have a little piece of plain Javascript code within the page to mainly get the TypeScript generated Javascript library firing.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; liveTickerViewModel&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; KaLog&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;LiveTickerViewModel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ko.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;applyBindings&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(liveTickerViewModel, $(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;#liveMessageTickerRoot&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;#connectionStateContainer&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;removeClass&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;hidden&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;liveTickerViewModel.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;startSignalRHub&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;($.connection);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As my TypeScript code does not have any view-code (id’s, selectors, etc.) in it I decided to have those four lines of code within the view/page itself so things are separated. It’s a matter of taste / programming-style.&lt;/p&gt;
&lt;p&gt;But anyway: the above code first instantiate my little view-model built with TypeScript (see below) then applies the Knockout databinding’s to that part of the page and remove the &lt;code&gt;hidden&lt;/code&gt; class from the surrounding container as now the right label should be ‘visible’. Removing the &lt;code&gt;hidden&lt;/code&gt; class will actually result in showing the surrounding DIV container including its content.&lt;/p&gt;
&lt;p&gt;Last but not least we tell our view-model to start the SignalR Hub.&lt;/p&gt;
&lt;h2 id=&quot;typescript-code&quot;&gt;TypeScript Code&lt;/h2&gt;
&lt;p&gt;Now the last part that makes it all work, the TypeScript view-model. Below you see the interesting parts of my view-model or let’s say the connection status indicator related parts of the code.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; KaLog&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; export &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LiveTickerViewModel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; * Represent the SignalR connection state.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connectionState: KnockoutObservable&amp;#x3C;number&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ko.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;observable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; * Initialize and start the SignalR hub.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; * @param connection&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; * @returns {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; startSignalRHub&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(connection: any) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; serverMonitoringHub&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connection.serverMonitoringHub;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connection.hub.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stateChanged&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SignalRStateChange&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;connectionStateChanged&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(state));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connection.hub.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; * Callback method triggered when the connection state of the SinalR connection changes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; * @param state&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; * @returns {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; connectionStateChanged&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(state: SignalRStateChange): void {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; stateConversion&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;connecting&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;connected&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;reconnecting&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;disconnected&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;SignalR state changed from: &apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stateConversion[state.oldState] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos; to: &apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stateConversion[state.newState]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;connectionState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(state.newState);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First we declare our view-model class &lt;code&gt;LiveTickerViewModel&lt;/code&gt;. Then we declare and initialize the property &lt;code&gt;connectionState&lt;/code&gt; which is a Knockout Observable which holds a value of type &lt;code&gt;number&lt;/code&gt;. We initialize it to disconnected.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;startSingalRHub()&lt;/code&gt; method we retrieve the SignalR client hub (generated by the SignalR Javascript Client). On the Hub we attach an event-handler for the &lt;code&gt;stateChanged&lt;/code&gt; event which calls the &lt;code&gt;connectionStateChanged()&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;connectionStateChanged()&lt;/code&gt; method does some console output (for debugging purpose) and then set the value of the observable property &lt;code&gt;connectionState&lt;/code&gt; to the new SingalR connection state. Setting this value will trigger the databinding from Knockout which result in updating the &lt;code&gt;visible&lt;/code&gt; attributes of our Bootstrap labels. Done.&lt;/p&gt;
&lt;p&gt;If you don’t need the debug console output you can inline the &lt;code&gt;this.connectionState(state)&lt;/code&gt; call straight into the &lt;code&gt;connection.hub.stateChanged&lt;/code&gt;-lambda and remove the entire &lt;code&gt;connectionStateChanged&lt;/code&gt;-method.&lt;/p&gt;</content:encoded></item><item><title>Configure IIS for passing static file requests to ASP.NET MVC</title><link>https://marcduerst.com/blog/configure-iis-for-passing-static-file-requests-to-asp-netmvc/</link><guid isPermaLink="true">https://marcduerst.com/blog/configure-iis-for-passing-static-file-requests-to-asp-netmvc/</guid><description>At my company we had several ASP.Net MVC projects what needed to serve some files with a custom MVC Controller/Action. The general problem with this is that ...</description><pubDate>Thu, 10 Jul 2014 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;configure-iis-for-passing-static-file-requests-toaspnetmvc&quot;&gt;Configure IIS for passing static-file requests to ASP.Net/MVC&lt;/h1&gt;
&lt;p&gt;At my company we had several ASP.Net MVC projects what needed to serve some files with a custom MVC Controller/Action. The general problem with this is that IIS tries hard to serve simple files like PDF’s, pictures etc. with its static-file handler which is generally fine but not for files or lets say file-content served by our own action.&lt;/p&gt;
&lt;p&gt;The goal is to switch off the static-file handling of IIS for some paths. One of the current projects came up with the following requirements so I did some research and how we can do this better then we did in past projects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Switch it off only for /Data/…&lt;/li&gt;
&lt;li&gt;Switch it off for ALL file-types as we don’t yet know what files the authors will store in &lt;em&gt;somewhere else&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This means that the default static-file handling of IIS must be switched off by some “magic” IIS config. In other apps we switched it off on a per file-type basis for the entire application. I finally came up with the following IIS-config (in web.config). It sets up a local configuration for the “data”-location only. Then I used a simple “*” wild-card as the path (yes, this is possible) to transfer requests to the ASP.Net. It looks like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FDAEB7;font-style:italic&quot;&gt;location&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; path&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FDAEB7;font-style:italic&quot;&gt;system.webServer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FDAEB7;font-style:italic&quot;&gt;handlers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#FDAEB7;font-style:italic&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;nostaticfile&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; path&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; verb&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;GET&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;System.Web.Handlers.TransferRequestHandler&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; preCondition&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;integratedMode,runtimeVersionv4.0&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#FDAEB7;font-style:italic&quot;&gt;handlers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#FDAEB7;font-style:italic&quot;&gt;system.webServer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#FDAEB7;font-style:italic&quot;&gt;location&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Tested with IIS 7.5.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alternative:&lt;/strong&gt;&lt;br&gt;
Instead a controller one could also use a custom HttpHandler for serving such special URL’s/Resources. In this project I decided using an action for this because of the central custom security which I needed for the /Data/… requests as well and got for free when using Action instead a HttpHandler.&lt;/p&gt;</content:encoded></item><item><title>ASP.NET MVC Areas</title><link>https://marcduerst.com/blog/asp-net-mvc-areas/</link><guid isPermaLink="true">https://marcduerst.com/blog/asp-net-mvc-areas/</guid><description>After some initial skepticism regarding Areas, I now use them more and more when building new Web-Applications using ASP.Net MVC. Therefore, I decided to cov...</description><pubDate>Wed, 09 Apr 2014 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;aspnet-mvc-areas&quot;&gt;ASP.Net MVC Areas&lt;/h1&gt;
&lt;p&gt;After some initial skepticism regarding Areas, I now use them more and more when building new Web-Applications using ASP.Net MVC. Therefore, I decided to cover some of my thoughts and experiences in a blog post so others may get some inspiration out of it.&lt;/p&gt;
&lt;p&gt;Before we start, here’s a link to a general introduction to the area feature of MVC. Check out this article if you are not yet familiar with Areas.&lt;/p&gt;
&lt;p&gt;Furthermore, this topic is based on MVC 5 and C# 4 but may also apply to older versions too as Areas are not really a new thing and were first introduced with MVC 2.&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Areas are intended to structure an MVC web application. Let’s say you’re building a line-of-business application. You may want to separate your modules on one hand from each other and on the other hand from central pieces of your web application like layouts, HTML helpers, etc.&lt;/p&gt;
&lt;p&gt;Therefore an area should be pretty much self-contained and should not have too much interaction with other areas—as little as possible—as otherwise the dependencies between the modules and their implementation grows more and more, undercutting separation, and resulting in less maintainability.&lt;/p&gt;
&lt;p&gt;How one draw the borders of each area depends on the need of the application and company. For example, modules can be separated by functionality or by developer/developer-team. In our line-of-business application, we may have an area for “Customer Management”, one for “Order Entry”, one for “Bookkeeping” and one for “E-Banking” as they have largely separate functionality and will likely be built by different developers or even teams.&lt;/p&gt;
&lt;p&gt;The nice thing about areas—besides modularization/organization of the app—is that they are built in MVC and therefore are supported by most tools like Visual Studio, R# and most libraries. On the negative side, I can count the lack of good support in the standard HtmlHelpers as one need to specify the area as a routing-object property and use the name of the area as a string. There is no dedicated parameter for the area. But to put that downside into perspective, this is only needed when making an URL to another area than the current one.&lt;/p&gt;
&lt;h2 id=&quot;application-modularization-using-areas&quot;&gt;Application Modularization using Areas&lt;/h2&gt;
&lt;p&gt;In my point of view, modularization using areas has two major advantages. The first one is the separation from other parts of the application and the second is the fact that area-related files are closer together in the Solution Explorer.&lt;/p&gt;
&lt;p&gt;The separation—apart from the usual separation advantages—is helpful for reviews as the reviewer can easily see what has changed within the area and what changed on the core level of the application and therefore needs an even-closer look. Another point of the separation is that for larger applications and teams it results in fewer merge conflicts when pushing to the central code repository as each team has its own playground. Last but not least, its nice for me as an application-developer because I know that when I make changes to my area only I will not break other developers’ work.&lt;/p&gt;
&lt;p&gt;As I am someone who uses the Solution Explorer a lot, I like the fact that with areas I normally have to scroll and search less and have a good overview of the folder- and file-tree of the feature-set I am currently working on. This happens because I moved all area-related stuff into the area itself and leave the general libraries, layouts, base-classes and helpers outside. This results in a less cluttered folder-tree for my areas, where I normally spend the majority of my time developing new features.&lt;/p&gt;
&lt;h3 id=&quot;tips-and-tricks&quot;&gt;Tips and Tricks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Move all files related to the area into the area itself including style-sheets (CSS, LESS, SASS) and client-side scripts (Javascript, TypeScript).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure bundles for your area or even for single pages within your area in the area itself. I do this in an enhanced area-registration file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enhance the default area registration to configure more aspects of your area.&lt;br&gt;
When generating links in global views/layouts use add the `area=“” routing attribute so the URL always points to the central stuff instead being area-relative.&lt;/p&gt;
&lt;p&gt;For example: if your application uses &lt;code&gt;@Html.ActionLink()&lt;/code&gt; in your global `_layout.cshtml?, use:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@Html.ActionLink(&amp;#x26;amp;quot;Go to home&amp;#x26;amp;quot;, &amp;#x26;amp;quot;Index&amp;#x26;amp;quot;, &amp;#x26;amp;quot;Home&amp;#x26;amp;quot;, new { area = &amp;#x26;amp;quot;&amp;#x26;amp;quot; });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;area-registration--start-up&quot;&gt;Area Registration / Start Up&lt;/h3&gt;
&lt;p&gt;And here is a sample of one of my application’s area registrations:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; BookkeepingAreaRegistration&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;AreaRegistration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; override&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AreaName&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;Bookkeeping&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; override&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RegisterArea&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;AreaRegistrationContext&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    RegisterRoutes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(context);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    RegisterBundles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(BundleTable.Bundles);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RegisterRoutes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;AreaRegistrationContext&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (context &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;context&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    context.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MapRoute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      &amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;Bookkeeping_default&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      &amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;Bookkeeping&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{controller}&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{action}&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{id}&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { controller &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;Home&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;, action &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;Index&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;, id &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; UrlParameter.Optional }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RegisterBundles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;BundleCollection&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; bundles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (bundles &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArgumentNullException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;bundles&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;      // Bookings Bundles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      bundles.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ScriptBundle&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;~/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bundles&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bookkeeping&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;booking&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;~/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Areas&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bookkeeping&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Scripts&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;booking.js&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      ));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      bundles.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; StyleBundle&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;~/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bookkeeping&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;css&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;booking&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Include&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;~/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Areas&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bookkeeping&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;booking.css&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amp;quot;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;      // Account Overview Bundle&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see in this example, I enhanced the area registration a little so area-specific bundles are registered in the area-registration too. I try to place all areas-specific start-up code in here.&lt;/p&gt;
&lt;h3 id=&quot;folder-structure&quot;&gt;Folder Structure&lt;/h3&gt;
&lt;p&gt;As I wrote in one of the tips, I strongly recommend storing all area-related files within the area’s folder. This includes style-sheets, client-side scripts (JS, TypeScript), content, controller, views, view-models, view-model builders, HTML Helpers, etc. My goal is to make an area self-contained so all work can be done within the area’s folder.&lt;/p&gt;
&lt;p&gt;So the folder structure of my MVC Apps look something like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;App_Start&lt;/li&gt;
&lt;li&gt;Areas
&lt;ul&gt;
&lt;li&gt;Content&lt;/li&gt;
&lt;li&gt;Controllers&lt;/li&gt;
&lt;li&gt;Core&lt;/li&gt;
&lt;li&gt;Models&lt;/li&gt;
&lt;li&gt;Builders&lt;/li&gt;
&lt;li&gt;Scripts&lt;/li&gt;
&lt;li&gt;Views&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;bin&lt;/li&gt;
&lt;li&gt;Content&lt;/li&gt;
&lt;li&gt;Controllers&lt;/li&gt;
&lt;li&gt;HtmlHelpers&lt;/li&gt;
&lt;li&gt;Models
&lt;ul&gt;
&lt;li&gt;Builders&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Scripts&lt;/li&gt;
&lt;li&gt;Views&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can see, each area is something like a mini-application within the main application.&lt;/p&gt;
&lt;h2 id=&quot;add-ons-using-areas-deployed-as-nuget-packages&quot;&gt;Add-ons using areas deployed as NuGet packages&lt;/h2&gt;
&lt;p&gt;Beside structuring an entire MVC Application, another nice usage is for hosting “add-on’s” in their own area.&lt;/p&gt;
&lt;p&gt;For example, lately I wrote a web-user-interface for the database-schema migration of our meta-data framework Quino. Instead of pushing it all in old-school web-resources and do binary deployment of them, I built it as an area. This area I’ve packed into a NuGet package (.nupkg) and published it to our local NuGet repo.&lt;/p&gt;
&lt;p&gt;Applications which want to use the web-based schema-migration UI can just install that package using the NuGet UI or console. The package will then add the area with all the sources I wrote and because the area-registration is called by MVC automatically, it’s ready to go without any manual action required. If I publish an update to the NuGet package applications can get these as usual with NuGet. A nice side-effect of this deployment is that the web application contains all the sources so developers can have a look at it if they like. It doesn’t just include some binary files. Another nice thing is that the add-on can define its own bundles which get hosted the same way as the MVC app does its own bundles. No fancy web-resources and custom bundling and minification is needed.&lt;/p&gt;
&lt;p&gt;To keep conflicts to a minimum with such add-on areas, the name should be unique and the area should be self-contained as written above.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Areas are a very nice thing in ASP.Net one can use for modularisation and therefore separation of building block of your web-application. They have some issues that could be improved (like the lack of typed support in the standard helpers) but they are definitivelly worth taking a closer look at. For my web-applications I use them mostly right from the beginning or as soon as I see that this will be a not trivial web-application or if multiple developers work on them. The add-on’s part described in the above section will be used much more for our central / common features that are available to multiple web-applications.&lt;/p&gt;</content:encoded></item></channel></rss>