PostSharp Blog Announcements, opinions, tips and tricks from PostSharp Technologies. https://blog.postsharp.net Wed, 07 Jan 2026 11:47:36 +0000 Wed, 07 Jan 2026 11:47:36 +0000 Jekyll v4.4.1 PostSharp 2026.0 Generally Available: Support for .NET 10, C# 14 and Extension Blocks <img src="https://blog.postsharp.net/assets/images/2026/2026-01-announcement/postsharp.svg" style="width: 100%"/> <p>Alongside <a href="https://metalama.net/blog/metalama-2026-0-ga">Metalama 2026.0</a>, we’re announcing the general availability of PostSharp 2026.0. This release brings full support for .NET 10 and C# 14, including proper handling of the new extension blocks syntax introduced in C# 14.</p> <h2 id="net-10-and-c-14">.NET 10 and C# 14</h2> <p>We’ve updated and tested PostSharp to fully support the .NET 10 SDK and C# 14 across all packages. You can now confidently use PostSharp with the latest .NET stack.</p> <h2 id="extension-blocks-support">Extension Blocks Support</h2> <p>C# 14 introduces extension blocks as an alternative syntax for defining extension methods. This new language feature required careful consideration in PostSharp to ensure predictable behavior.</p> <p>By default, multicast attributes now skip extension block members. This prevents aspects from being unintentionally applied to compiler-generated metadata associated with extension blocks.</p> <p>For scenarios where you do want to target extension block members, we’ve added the <code class="language-plaintext highlighter-rouge">AllowExtensionBlockMembers</code> property to both <code class="language-plaintext highlighter-rouge">MulticastAttribute</code> and <code class="language-plaintext highlighter-rouge">MulticastAttributeUsageAttribute</code>. Setting this property to <code class="language-plaintext highlighter-rouge">true</code> enables your aspects to target extension block members explicitly.</p> <p>Additionally, developers using <code class="language-plaintext highlighter-rouge">IAspectProvider</code> or <code class="language-plaintext highlighter-rouge">IAdviceProvider</code> interfaces can use the new <code class="language-plaintext highlighter-rouge">ReflectionHelper.IsExtensionBlockMetadata</code> utility method to identify compiler-generated metadata associated with extension blocks.</p> <h2 id="updated-framework-baselines">Updated Framework Baselines</h2> <p>We’ve raised the minimum supported frameworks to reflect the current .NET ecosystem:</p> <ul> <li><strong>.NET Standard 2.0</strong> (minimum)</li> <li><strong>.NET Framework 4.7.0</strong> (minimum)</li> <li><strong>.NET 6.0</strong> (minimum for .NET Core-based projects)</li> </ul> <p>All pre-2017 target frameworks and obsolete .NET Core versions that have lost mainstream support have been removed. Please consult the <a href="https://doc.postsharp.net/introduction/whatsnew/whats-new-20260">breaking changes documentation</a> for complete migration guidance.</p> <h2 id="conclusion">Conclusion</h2> <p>PostSharp 2026.0 continues our commitment to keeping PostSharp compatible with the latest .NET releases. While our new feature development is focused on <a href="/metalama-2026-0-ga">Metalama</a>, we remain dedicated to ensuring that PostSharp users can stay current with the evolving .NET platform.</p> <p>Happy meta-programming with PostSharp!</p> <p> This article was first published on a <a href="https://blog.postsharp.net">https://blog.postsharp.net</a> under the title <a href="https://blog.postsharp.net/postsharp-2026-0-ga">PostSharp 2026.0 Generally Available: Support for .NET 10, C# 14 and Extension Blocks</a>. </p> Wed, 07 Jan 2026 07:00:00 +0000 Wed, 07 Jan 2026 11:45:59 +0000 https://blog.postsharp.net/postsharp-2026-0-ga https://blog.postsharp.net/postsharp-2026-0-ga featured PostSharp https://blog.postsharp.net/assets/images/2026/2026-01-announcement/postsharp.svg Security Notice: Data Leak Affecting a Limited Number of Accounts <p>We regret to inform you of a data leak that occurred on the <strong>PostSharp Customer Portal</strong> between <strong>Wednesday, September 3rd, and Tuesday, September 9th</strong>.</p> <h3 id="who-is-affected">Who is affected?</h3> <p>A total of <strong>38 customer accounts</strong> were impacted. If your account was affected, you will:</p> <ol> <li>Receive a personal notification email within the next 24 hours.</li> <li>Notice that you can no longer sign in to the portal using your license keys.</li> </ol> <h3 id="what-data-was-leaked">What data was leaked?</h3> <p>Only the content of the <a href="https://www.postsharp.net/account">https://www.postsharp.net/account</a> page of the portal was exposed, including:</p> <ul> <li>Company name and billing address (or customer name and address for natural persons)</li> <li>All subscription dates, number of users, licensed products, and support level</li> <li>All license keys for PostSharp and Metalama</li> </ul> <h3 id="what-was-not-leaked">What was <em>not</em> leaked?</h3> <ul> <li>Contact lists or email addresses</li> <li>Prices, invoices, or quotes</li> <li>Support tickets</li> <li>Source code (never uploaded to our servers)</li> </ul> <h3 id="who-accessed-the-data">Who accessed the data?</h3> <p>At most, <strong>one other PostSharp customer</strong> may have received your data in error.</p> <h3 id="how-did-this-happen">How did this happen?</h3> <p>A <strong>caching error</strong> occurred in the daily job that sends subscription renewal notifications, causing account data to be sent to the wrong recipient. The first customer of the batch received all emails.</p> <h3 id="timeline-of-events">Timeline of events</h3> <ul> <li><strong>Wed 9/3, 11:00 AM</strong> – First incorrect email sent.</li> <li><strong>Mon 9/8, 8:00 PM</strong> – Data leak reported by the receiving customer.</li> <li><strong>Tue 9/9, 2:00 PM</strong> – Report read and incident confirmed.</li> <li><strong>Tue 9/9, 4:30 PM</strong> – Credentials invalidated and issue remediated.</li> </ul> <h3 id="how-we-fixed-it">How we fixed it?</h3> <ul> <li>All past <strong>magic URLs</strong> were invalidated by rotating the salt for each affected account.</li> <li>License keys exposed in the leak were <strong>disabled for authentication</strong> to the portal.</li> <li>The caching bug was fixed.</li> </ul> <h3 id="do-you-need-to-take-action">Do you need to take action?</h3> <ul> <li><strong>No action is required</strong>. Your license keys will continue to work normally with PostSharp and Metalama products.</li> <li>If you prefer, we can issue <strong>new license keys</strong> on request, to ensure that any leaked key cannot be used by another party.</li> </ul> <h3 id="how-to-log-in-now">How to log in now?</h3> <p>If your license keys no longer work for portal login:</p> <ul> <li>Use <strong>email authentication</strong> (one-time PIN or magic link) for one of your account contacts.</li> <li>If you do not know your contact, please write to <strong><a href="mailto:hello@postsharp.net">hello@postsharp.net</a></strong> from your work email.</li> </ul> <p>We take full responsibility for this incident and sincerely apologize for the error. We are committed to ensuring it does not happen again.</p> <p> This article was first published on a <a href="https://blog.postsharp.net">https://blog.postsharp.net</a> under the title <a href="https://blog.postsharp.net/2025-09-09-security-notice">Security Notice: Data Leak Affecting a Limited Number of Accounts</a>. </p> Sun, 07 Sep 2025 23:00:01 +0000 Wed, 07 Jan 2026 11:45:59 +0000 https://blog.postsharp.net/2025-09-09-security-notice https://blog.postsharp.net/2025-09-09-security-notice PostSharp https://blog.postsharp.net/assets/images/blog/ps-no-featimg-16x9.jpg Breaking Update of PostSharp Caching adapter for Redis in 2025.1 <img src="https://blog.postsharp.net/assets/images/2025/2025-09-redis-caching/caching.svg" style="width: 100%"/> <p>We have released a refactored version of <code class="language-plaintext highlighter-rouge">PostSharp.Patterns.Caching.Backends.Redis</code> in PostSharp 2025.1 to address a reliability issue that could surface in multi-node Redis deployments (master/replica or cluster) when cache dependencies are enabled under sustained load. The fix required a redesign of the internal data schema, which is why this is a breaking change (one-time cache purge). Outside of that purge, the upgrade is straightforward and brings measurable gains in performance, consistency, and resilience.</p> <p>Impact at a glance:</p> <ul> <li>If you run multi-node Redis with dependencies, the update removes a potential failure mode.</li> <li>You only need a one-time cache purge, and you’ll still benefit from performance and diagnostics improvements.</li> <li>There is no risk of user data loss; only old cached entries stay in the database until purged.</li> <li>No impact for the other backends.</li> </ul> <h2 id="who-is-affected">Who is affected?</h2> <ul> <li><strong>Affected by the bug:</strong> <ul> <li>Applications that use <code class="language-plaintext highlighter-rouge">PostSharp.Patterns.Caching.Backends.Redis</code> with support for dependencies in a Redis master/replica or cluster setup.</li> </ul> </li> <li><strong>Affected by the refactoring:</strong> <ul> <li>All applications that use <code class="language-plaintext highlighter-rouge">PostSharp.Patterns.Caching.Backends.Redis</code>, with or without support for dependencies, are affected by the redesign of the data schema. You must purge the cache after the update, and there is no other impact. All versions prior to 2025.1.7 are affected.</li> </ul> </li> </ul> <p>Customers using <code class="language-plaintext highlighter-rouge">Metalama.Patterns.Caching.Backends.Redis</code> are affected by this issue too, and the solution has not yet been ported to Metalama. Please contact us if it matters to you.</p> <h2 id="what-was-wrong">What was wrong?</h2> <p>The previous design of the <code class="language-plaintext highlighter-rouge">RedisCachingBackend</code> relied on a retry loop in <code class="language-plaintext highlighter-rouge">GetItem</code> operations to retrieve a consistent snapshot of the cache item, which includes both the cache value and its dependencies, stored in separate Redis keys. Under heavy load in a master/replica setup, this loop could exhaust its iterations and fail.</p> <p>The consistent snapshot of value and dependencies was required because recursive dependencies (when a cached method calls another already cached method) were flattened in the <code class="language-plaintext highlighter-rouge">SetItem</code> operation, so the <code class="language-plaintext highlighter-rouge">RemoveItem</code> and <code class="language-plaintext highlighter-rouge">InvalidateItem</code> operations did not need to operate recursively. This was a poor design choice.</p> <p>The previous component was only tested in a single-node Redis topology. We believe the root cause was a lack of testing in multi-node topologies under high load.</p> <h2 id="how-was-this-fixed">How was this fixed?</h2> <p>We redesigned the data schema so <code class="language-plaintext highlighter-rouge">GetItem</code> never needs to iterate:</p> <ul> <li>Dependencies are no longer flattened. The <code class="language-plaintext highlighter-rouge">RemoveItem</code> and <code class="language-plaintext highlighter-rouge">InvalidateItem</code> operations now work recursively.</li> <li>Cache keys (a single logical cache item requires several Redis keys) are now versioned, so we don’t need loops to ensure read consistency.</li> </ul> <h2 id="what-else-has-been-improved">What else has been improved?</h2> <p>Since a major refactoring was required to implement the new data schema, we went the extra mile and made the component more resilient in high-load production environments:</p> <ul> <li><strong>Performance improvements</strong> due to the new design of the Redis data schema that is always observationally consistent for read operations.</li> <li><strong>Key compression (hashing).</strong> Enable this feature by assigning the <code class="language-plaintext highlighter-rouge">CachingServices.DefaultKeyBuilder</code> property.</li> <li><strong>More resilient</strong> thanks to new behaviors controlled by the following properties on the <code class="language-plaintext highlighter-rouge">RedisCachingBackendConfiguration</code> object: <ul> <li><strong>Exception handling:</strong> <code class="language-plaintext highlighter-rouge">RedisCachingBackendConfiguration.ExceptionHandlingPolicy</code>.</li> <li><strong>Retry policies:</strong> <code class="language-plaintext highlighter-rouge">RedisCachingBackendConfiguration.BackgroundRecoveryRetryPolicy</code>, <code class="language-plaintext highlighter-rouge">RedisCachingBackendConfiguration.BackgroundTasksRetryPolicy</code>, <code class="language-plaintext highlighter-rouge">RedisCachingBackendConfiguration.TransactionRetryPolicy</code>.</li> <li><strong>Concurrency control:</strong> <code class="language-plaintext highlighter-rouge">BackgroundTasksMaxConcurrency</code> and <code class="language-plaintext highlighter-rouge">InvalidationMaxConcurrency</code>.</li> <li><strong>Node selection:</strong> <code class="language-plaintext highlighter-rouge">ReadCommandFlags</code> and <code class="language-plaintext highlighter-rouge">WriteCommandFlags</code>, defaulting to <code class="language-plaintext highlighter-rouge">PreferReplica</code> and <code class="language-plaintext highlighter-rouge">PreferMaster</code>, respectively.</li> </ul> </li> <li><strong>Support for sharding clusters,</strong> with keys containing taghashes. Tested on a 3+3 cluster.</li> <li><strong>Support for dependencies</strong> with a very large number of dependent cache items.</li> <li><strong>GC process:</strong> <ul> <li>Detection of overloads and automatic temporary disabling.</li> <li>Periodic background cleanups to handle situations that were not detected by processing keyspace notifications in real time.</li> </ul> </li> <li><strong>Keys contain the PostSharp Caching schema version</strong> for safe updates.</li> <li><strong>Fixed bugs</strong> with sliding expiration.</li> <li><strong>Improved <a href="https://doc.postsharp.net/caching/backends/caching-redis">documentation</a>.</strong></li> </ul> <h2 id="what-changes-are-breaking">What changes are breaking?</h2> <ul> <li>The data schema has changed, so you must purge the old version’s cache; otherwise it will contain permanently unreachable data (garbage) forever.</li> <li>The <code class="language-plaintext highlighter-rouge">CacheValue.Dependencies</code> and <code class="language-plaintext highlighter-rouge">CacheItem.Dependencies</code> properties now contain first-level dependencies rather than all recursive dependencies. These objects are largely implementation details and do not surface to the aspect-oriented API of PostSharp Caching.</li> </ul> <h2 id="how-to-update">How to update?</h2> <ol> <li>Update all PostSharp packages to <code class="language-plaintext highlighter-rouge">2025.1.8</code> and deploy your application.</li> <li>Purge the cache using Redis’s <code class="language-plaintext highlighter-rouge">FLUSHDB</code> command after your old application has been undeployed.</li> </ol> <p>If you ignore this post and only update the package, the Redis database will contain the data of the old version forever, since the dependency-management keys are set to never expire.</p> <h2 id="read-more">Read more</h2> <p>For details about the refactored PostSharp Caching for Redis, see our <a href="https://doc.postsharp.net/caching/backends/caching-redis">documentation</a>.</p> <h2 id="conclusion">Conclusion</h2> <p>PostSharp Caching for Redis now runs on a more robust, versioned schema that removes a reliability edge case and improves performance and consistency across single-node, replicated, and sharded clusters when dependency support is enabled. The component has been overhauled for better observability and resilience. The only required action is a one-time cache purge after upgrading to 2025.1.8 or later.</p> <p>If you rely on the Metalama Redis backend, let us know so we can prioritize porting the same improvements.</p> <p>Thanks to customers who surfaced the scenario early—enjoy the improved backend.</p> <p> This article was first published on a <a href="https://blog.postsharp.net">https://blog.postsharp.net</a> under the title <a href="https://blog.postsharp.net/redis-caching-update">Breaking Update of PostSharp Caching adapter for Redis in 2025.1</a>. </p> Mon, 01 Sep 2025 23:00:01 +0000 Wed, 07 Jan 2026 11:45:59 +0000 https://blog.postsharp.net/redis-caching-update https://blog.postsharp.net/redis-caching-update PostSharp https://blog.postsharp.net/assets/images/2025/2025-09-redis-caching/caching.svg PostSharp Is Now Source Available <img src="https://blog.postsharp.net/assets/images/2025/2025-08-source-available/postsharp.svg" style="width: 100%"/> <p>This spring we open-sourced Metalama. Continuing that push for transparency and dependability, PostSharp’s source code is now available to enterprise customers at no extra cost. You can access a read-only mirror of our primary Git repository, including every version back to 1.0 (2009). It’s an exact copy of the repo we use to build the product — down to the commas. We also provide a supported, Docker-based build for versions 2024.0, 2025.0, and 2025.1. Those versions are no longer obfuscated in our public builds.</p> <p>The code is released under a permissive, proprietary source-available license. You can modify, build, and distribute the software, provided users of the modified code hold a valid PostSharp license.</p> <p>We are releasing our source code with the following use cases in mind:</p> <ul> <li>Troubleshooting</li> <li>Supply chain security</li> <li>Supply chain resilience</li> </ul> <p>In an era of tightening regulations (like the EU’s Cyber Resilience Act) and increased focus on software supply chain security, transparency isn’t optional — it’s necessary.</p> <h2 id="who-qualifies">Who qualifies</h2> <p>To access the source, you need an Enterprise E1 support plan or higher, which is included in:</p> <ul> <li>a 10-user subscription of PostSharp Ultimate, or</li> <li>a 15-user subscription of PostSharp Framework.</li> </ul> <p>There’s no additional cost — it’s included in your subscription.</p> <p>If you have fewer users but need source access, add more users to your subscription.</p> <p>See our <a href="https://www.postsharp.net/support/policies/sla">support policies</a> for a description of our support levels and their eligibility.</p> <p>Before getting access to the repo, you must sign a Non-Disclosure &amp; Non-Competing Agreement.</p> <h2 id="use-case-1-troubleshooting">Use case 1. Troubleshooting</h2> <p>You now have full visibility into the source to troubleshoot issues.</p> <p>We’ve disabled obfuscation in all maintained versions. When decompilation isn’t sufficient, you can read the original source.</p> <p>Note: SourceLink is not available yet.</p> <h2 id="use-case-2-supply-chain-security">Use case 2. Supply chain security</h2> <p>Supply chain security isn’t just about trusting suppliers — it’s about trusting the code you run. With full access to our source, you can run your own analysis tools and assess the code’s quality.</p> <p>Auditing the source alone isn’t enough. You need to guarantee that the binaries you execute were built from that audited source. That means you should be able to build the code yourself. To make that practical, we provide a Docker-based build that requires only Windows containers.</p> <p>Once you’ve built the packages, you have two theoretical options to verify the chain of custody:</p> <ol> <li>Use the packages you built yourself instead of sourcing them from <code class="language-plaintext highlighter-rouge">nuget.org</code>, or</li> <li>Compare your packages with those sourced publicly.</li> </ol> <p>In practice, our public binaries won’t be bitwise identical to what you build because our public builds are signed with Authenticode using a timestamp and a private certificate we cannot share. For that reason, only the first option — using your own built packages — is available to guarantee the chain of custody.</p> <p>You can use <a href="https://learn.microsoft.com/en-us/nuget/consume-packages/package-source-mapping">Package Source Mapping</a> (a NuGet client option) to ensure packages are sourced from your private builds rather than PostSharp’s public ones.</p> <h2 id="use-case-3-supply-chain-resilience">Use case 3. Supply chain resilience</h2> <p>Companies rely on PostSharp for mission-critical applications and need contingency plans for scenarios such as product end-of-life, company closure, or temporary inability of the supplier to deliver fixes or platform updates. By giving enterprise customers full source access, we enable practical contingency plans. You have the legal right and technical capability to:</p> <ul> <li>Fork and maintain your own version of PostSharp if our support becomes unavailable</li> <li>Apply critical security patches without waiting for official updates</li> <li>Maintain older versions beyond their official support lifecycle</li> <li>Ensure business continuity even in worst-case scenarios</li> </ul> <p>Section 9 of the <a href="https://www.postsharp.net/downloads/legal/PostSharp%20License%20and%20Support%20Services%20Agreement%202025-Q2.docx">license agreement</a> provides the legal framework for these business continuity scenarios, so you can be confident your critical systems won’t be held hostage by vendor dependencies.</p> <h2 id="how-does-it-work">How does it work?</h2> <h3 id="1-getting-access">1. Getting access</h3> <ol> <li>Sign in to the <a href="https://www.postsharp.net/account">customer portal</a>.</li> <li>Check your support entitlements. You must have an Enterprise support plan (E1 or higher).</li> <li>Go to the <a href="https://www.postsharp.net/account/source-access">source access</a> page.</li> <li>Sign the Non-Disclosure/Non-Competing Agreement online (or offline).</li> <li>Allow one business day for review and account update.</li> <li>Return to the <a href="https://www.postsharp.net/account/source-access">source access</a> page and create Git users and passwords.</li> <li>Clone the repositories using Git.</li> <li>Check out one of the support release branches: <code class="language-plaintext highlighter-rouge">release/2024.0</code>, <code class="language-plaintext highlighter-rouge">release/2025.0</code>, or <code class="language-plaintext highlighter-rouge">release/2025.1</code>.</li> </ol> <h3 id="2-building-packages">2. Building packages</h3> <p>See <code class="language-plaintext highlighter-rouge">README.md</code> in the cloned repo for details about requirements and build instructions.</p> <ol> <li>You need a Windows 11 machine with Docker Desktop configured for Windows containers.</li> <li>Open a PowerShell prompt and execute <code class="language-plaintext highlighter-rouge">./Build-Docker.ps1</code>.</li> <li>Wait — initial image creation can take over an hour on a high-end notebook; subsequent builds may take around 30 minutes.</li> </ol> <h2 id="getting-support">Getting support</h2> <p>We’re here to help. Enterprise customers can email support@postsharp.net for help with source access, builds, or questions about the source-available license. Customers with Enterprise E2 support plans or higher can also reach us on Microsoft Teams or Slack for real-time collaboration and faster resolution of complex issues.</p> <h2 id="limitations">Limitations</h2> <ul> <li>The source code of Visual Studio Tools for Metalama and PostSharp is currently not available.</li> <li>Our obligation is limited to a successful Docker build from the unmodified source: <ul> <li>Although the repo includes CI/CD scripts, running those tests or configuring CI/CD infrastructure is not supported.</li> <li>We do not provide support for modified source code.</li> </ul> </li> <li>We only support building release branches for currently maintained versions.</li> </ul> <h2 id="conclusion">Conclusion</h2> <p>Publishing PostSharp’s source is the final step in our 2025 transparency and dependability initiative, following Metalama’s earlier move to open source. Eligible customers now have full access to the source, improving supplier security and resilience.</p> <p>If you want access, visit the <a href="https://www.postsharp.net/account">PostSharp Customer Portal</a> to verify your eligibility, complete the NDA/NCA process, and gain repository access.</p> <p> This article was first published on a <a href="https://blog.postsharp.net">https://blog.postsharp.net</a> under the title <a href="https://blog.postsharp.net/postsharp-source-available">PostSharp Is Now Source Available</a>. </p> Thu, 07 Aug 2025 23:00:01 +0000 Wed, 07 Jan 2026 11:45:59 +0000 https://blog.postsharp.net/postsharp-source-available https://blog.postsharp.net/postsharp-source-available PostSharp https://blog.postsharp.net/assets/images/2025/2025-08-source-available/postsharp.svg Announcing Metalama 2025.1: Going Open Source! <img src="https://blog.postsharp.net/assets/images/2025/2025-05-announcements/metalama.svg" style="width: 100%"/> <p>Today, we’re excited to announce that Metalama 2025.1, our first open-source release, is now generally available! With this milestone, Metalama gets its own dedicated website at <a href="https://metalama.net">https://metalama.net</a>. Be sure to check out the <a href="https://metalama.net/blog/metalama-open-source">announcement</a> to learn more about this transition and why it is so significant. This post covers the details of the changes in licensing, pricing, and support, and what they mean for our customers. Our goal is to make Metalama more accessible while continuing to provide productivity features and robust support for those who choose our premium plans.</p> <p>Our objective with this move is to make our tools more accessible while offering enhanced support and services to customers who opt for higher-tier commercial plans, ensuring a balanced and sustainable approach for all users.</p> <blockquote class="note"> <p>This article is part of a 3-post series announcing the launch of our 2025.1 versions:</p> <ul> <li><a href="https://metalama.net/blog/metalama-open-source">Metalama Is Now Open Source – Adding Full Meta-Programming Capabilities to C#</a>: an introduction to Metalama and our open-source vision.</li> <li><strong>Announcing Metalama 2025.1: Going Open Source!</strong>: changes in licensing and support terms for Metalama.</li> <li><a href="/postsharp-2025-1">Announcing PostSharp 2025.1</a>: changes in licensing and support terms for PostSharp.</li> </ul> </blockquote> <h2 id="tldr">TL;DR</h2> <ul> <li>The Metalama product line has been reorganized, with most of the code now open source. IDE tooling is now free for individuals, non-commercial use, or companies with up to three users.</li> <li>Starting with version 2025.1, only the <em>latest</em> versions of our products will be available under an open-source or free license. Maintenance of older versions is reserved for commercial or enterprise customers based on their service level.</li> </ul> <p>If you have any questions or concerns regarding this transition, please contact us at <a href="mailto:hello@postsharp.net">hello@postsharp.net</a>.</p> <p class="warning">These changes would not have been possible without breaking changes. Please check the <a href="https://doc.metalama.net/conceptual/release-notes/release-notes-2025-1">release notes</a> for details.</p> <h2 id="open-source-transition">Open-source transition</h2> <p>Metalama is now primarily <strong>free and open source</strong>, released under the MIT license. The following components remain commercial:</p> <ul> <li>Visual Studio extensions for Metalama.</li> <li>Architecture validation (formerly the <code class="language-plaintext highlighter-rouge">Metalama.Framework.Validation</code> and <code class="language-plaintext highlighter-rouge">Metalama.Extensions.Architecture</code> namespaces).</li> <li>Code fix toolkits (formerly the <code class="language-plaintext highlighter-rouge">Metalama.Framework.CodeFixes</code> namespace).</li> <li>Redis and Azure adapters for <code class="language-plaintext highlighter-rouge">Metalama.Patterns.Caching</code>.</li> </ul> <h2 id="new-product-catalogue">New product catalogue</h2> <p>The Metalama product line has been restructured to align with our new open-source business model, making our tools and frameworks free for individuals, small teams, and non-commercial use, while offering premium services and packages to larger organizations.</p> <p>We have introduced a simplified product catalogue:</p> <ul> <li><strong>Metalama Community</strong> — A <strong>free</strong> edition, including Visual Studio tools, for individuals, non-commercial use, and organizations with up to three users.</li> <li><strong>Metalama Professional</strong> — A full-featured edition for commercial use.</li> <li><strong>Metalama Enterprise</strong> — Includes all Professional features, plus <strong>enhanced support and service benefits</strong>.</li> </ul> <p>For a detailed comparison of editions, visit: <a href="https://www.postsharp.net/pricing/metalama">https://www.postsharp.net/pricing/metalama</a>.</p> <h2 id="transitioning-your-existing-subscriptions">Transitioning your existing subscriptions</h2> <p>Unless you are using Metalama Free, <strong>your current license key will continue to work</strong> with Metalama 2025.1 without any loss of functionality. Here’s how the transition affects different licenses:</p> <ul> <li><strong>Metalama Free</strong>: This edition has been retired, and its license will not work with Metalama 2025.1. Your options are: <ul> <li>Use only the open-source components.</li> <li>Switch to Metalama Community.</li> <li>Upgrade to a Metalama Professional license.</li> </ul> </li> <li> <p><strong>Metalama Professional</strong>: Now the full-featured edition with unlimited functionality, but with limited support.</p> </li> <li><strong>Metalama Starter</strong> and <strong>Metalama Ultimate</strong>: These editions have been retired. Your current license key will function as Metalama Professional in the new version, but you’ll need to convert your subscription to Metalama Professional upon renewal.</li> </ul> <h2 id="pricing-overhaul">Pricing overhaul</h2> <p>We’ve restructured Metalama’s pricing to reflect the new model:</p> <ul> <li><strong>Metalama Professional</strong>: First-year pricing is $89 for individuals and $295 for businesses.</li> <li><strong>Volume Discounts</strong> are no longer available. Larger teams are now served by Metalama Enterprise, which offers four tiers with varying benefits and team sizes.</li> </ul> <p><a href="https://www.postsharp.net/pricing/metalama">See Metalama pricing</a>.</p> <p class="note">If the pricing changes negatively impact you and your software licensing budget has already been approved, please contact us. We’ll honor the previous pricing to ensure a smooth transition.</p> <h2 id="support-model-updates">Support model updates</h2> <p>We have updated our support model to align with the open-source transition.<br /> These changes apply <strong>only to new or renewed subscriptions</strong>. Existing contracts remain under the previous License and Support Services Agreement (LSSA).</p> <h3 id="servicing-phases">Servicing phases</h3> <p>We have introduced <strong>servicing phases</strong> to clarify the lifecycle of Metalama versions (<code class="language-plaintext highlighter-rouge">YYYY.N</code>):</p> <ul> <li><strong>Current:</strong> Supported until the next version is released.</li> <li><strong>Extended:</strong> Supported for six months after the next release.</li> <li><strong>Long-Term Support (LTS):</strong> Supported for two years after the next LTS release or until the underlying platform reaches end-of-life.</li> </ul> <p>Starting with version 2025.1, only the <strong>current</strong> version will be maintained under the open-source model. Access to <strong>Extended</strong> and <strong>LTS</strong> builds will require a commercial license.</p> <p class="note">Updates are never mandatory. Once a build becomes eligible for you, it will remain accessible indefinitely.</p> <p>Note that maintenance builds of previous versions remain accessible to all users, regardless of support level.</p> <p>For more details, visit: <a href="https://www.postsharp.net/support/policies/versions">Versioning Policies</a>.</p> <h3 id="premium-support-tiers">Premium support tiers</h3> <p>We have formalized premium support into clear tiers, offering benefits such as:</p> <ul> <li>Private support tickets</li> <li>Access to Extended and LTS builds</li> <li>Faster response times and issue escalation</li> <li>Defined number of technical contacts</li> <li>Access to proprietary source code</li> <li>Advisory and video calls</li> <li>GDPR/vendor form assistance</li> <li>Private Slack or Teams channels</li> <li>Priority bug fixes and remote debugging</li> <li>EULA amendments and regression shields</li> <li>License audit waivers</li> <li>Open-source sponsorship tiers</li> </ul> <p>For <em>newly acquired or renewed subscriptions</em>, the support level is determined by the edition (Professional or Enterprise tiers E1–E4). For <em>existing subscriptions</em>, the support level is determined by the number of users.</p> <p>Please visit <a href="https://www.postsharp.net/support/policies/sla">Service Levels</a> for details regarding support benefits and how they map to product editions.</p> <p>To know your current support level, please visit the <a href="https://www.postsharp.net/subscriptions">customer portal</a>.</p> <h3 id="source-code-access">Source code access</h3> <p>Metalama’s open-source code is now available on <a href="https://github.com/metalama/Metalama">GitHub</a> under the MIT license. Additionally, Enterprise customers gain exclusive access to private GitHub repositories for:</p> <ul> <li>Premium packages (e.g., architecture validation, code fix toolkits, Redis and Azure adapters).</li> <li>Core packages once they enter Extended Support or LTS phases.</li> </ul> <p>To request access, check your support level in the <a href="https://www.postsharp.net/subscriptions">customer portal</a> and email us at <a href="mailto:hello@postsharp.net">hello@postsharp.net</a> with the GitHub usernames to be granted access.</p> <h2 id="conclusion">Conclusion</h2> <p>By transitioning Metalama to an open-source business model, we aim to promote greater awareness and adoption of meta-programming within the developer community.</p> <p>We believe that vendor-led open source strikes the right balance between transparency and dependability: developers gain the ability to inspect and contribute to the code, while the vendor ensures long-term support through a sustainable commercial offering. If the vendor fails to uphold its commitment to maintaining the software, the community has the freedom to step in and take over.</p> <p>Our goal is to create a fair balance between open-source accessibility, proprietary features, and premium services. We’ve worked hard to ensure these changes benefit as many users as possible. However, if you feel these changes impact you unfairly, please don’t hesitate to reach out. We’re committed to finding a solution that works for you.</p> <p>Thank you for your continued support, and happy meta-programming!</p> <p>-gael</p> <p> This article was first published on a <a href="https://blog.postsharp.net">https://blog.postsharp.net</a> under the title <a href="https://blog.postsharp.net/metalama-2025-1">Announcing Metalama 2025.1: Going Open Source!</a>. </p> Fri, 02 May 2025 04:00:01 +0000 Wed, 07 Jan 2026 11:45:59 +0000 https://blog.postsharp.net/metalama-2025-1 https://blog.postsharp.net/metalama-2025-1 Metalama https://blog.postsharp.net/assets/images/2025/2025-05-announcements/metalama.svg Announcing PostSharp 2025.1 <img src="https://blog.postsharp.net/assets/images/2025/2025-05-announcements/postsharp.svg" style="width: 100%"/> <p>Today’s big announcement is that <a href="/metalama-2025-1">we are releasing Metalama 2025.1</a>, our first open-source release. Be sure to visit the new website at <a href="https://metalama.net">https://metalama.net</a> and check out the <a href="https://metalama.net/blog/metalama-open-source">open-source announcement</a>. Alongside this, we’re also launching PostSharp 2025.1 to align with our updated business model. This article explains the changes in licensing and support.</p> <blockquote class="note"> <p>This article is part of a 3-post series announcing the launch of our 2025.1 versions:</p> <ul> <li><a href="https://metalama.net/blog/metalama-open-source">Metalama Is Now Open Source – Adding Full Meta-Programming Capabilities to C#</a>: an introduction to Metalama and to our open-source vision.</li> <li><a href="/metalama-2025-1">Announcing Metalama 2025.1: Going Open Source!</a>: changes in licensing and support terms for Metalama.</li> <li><strong>Announcing PostSharp 2025.1</strong>: changes in licensing and support terms for PostSharp.</li> </ul> </blockquote> <p class="note">Your current subscription and license keys remain unaffected by these updates. All changes will take effect upon renewal.</p> <h2 id="product-consolidation">Product consolidation</h2> <p>To simplify our product lineup, the following products will no longer be available for separate purchase:</p> <ul> <li><strong>PostSharp Logging</strong> is now included in <strong>PostSharp Framework</strong>.</li> <li><strong>PostSharp MVVM</strong>, <strong>Caching</strong>, and <strong>Threading</strong> are now exclusively part of <strong>PostSharp Ultimate</strong>.</li> </ul> <p>If you already have a license or subscription for these products, don’t worry: your access will remain unchanged. You can continue to renew your subscription or add new users as needed.</p> <h2 id="pricing-updates">Pricing updates</h2> <p>For the first time since 2016, we’ve adjusted PostSharp pricing to reflect currency fluctuations:</p> <ul> <li><strong>USD prices</strong> have increased by <strong>5–10%</strong>, depending on the product.</li> <li><strong>EUR prices</strong> have been adjusted by <strong>-5% to +5%</strong>, depending on the product.</li> </ul> <p>For detailed pricing information, visit: <a href="https://www.postsharp.net/pricing/postsharp">https://www.postsharp.net/pricing/postsharp</a>.</p> <h2 id="servicing-phases">Servicing phases</h2> <p>Until now, we maintained legacy versions and made bug-fix releases available to everyone. Starting with PostSharp 2025.1, access to maintenance builds for legacy versions will be reserved for commercial customers. This change aligns PostSharp with Metalama’s support model.</p> <p>We’ve introduced the concept of <strong>servicing phases</strong> to clarify the lifecycle of PostSharp versions (<code class="language-plaintext highlighter-rouge">YYYY.N</code>):</p> <ul> <li><strong>Current:</strong> Supported until the next version is released. Available to all users, including those with a free edition.</li> <li><strong>Extended:</strong> Supported for six months after the next release (instead of two months prior to 2025.1). Available to all commercial customers.</li> <li><strong>Long-Term Support (LTS):</strong> Supported for two years after the next LTS release or until the underlying platform reaches end-of-life. Available to customers with Enterprise support.</li> </ul> <p>Starting with version 2025.1, only the <strong>current</strong> version will be available to PostSharp Essentials users. Access to <strong>Extended</strong> builds will require a commercial license, and <strong>LTS</strong> builds will require an Enterprise support level.</p> <p class="note">Updates are never mandatory. Once a build becomes eligible for you, it will remain accessible indefinitely.</p> <p>Maintenance builds of previous versions will remain available to all users, regardless of support level.</p> <p>For more details, visit: <a href="https://www.postsharp.net/support/policies/versions">Versioning Policies</a>.</p> <h2 id="support-levels">Support levels</h2> <p>You might be wondering about the new Enterprise support level.</p> <p>Previously, we didn’t have a formalized approach to SLAs, and we informally prioritized customers based on their expenditures. Moving forward, your support level will depend on the number of licenses you acquire. For PostSharp Framework, Enterprise support starts at 15 users; for PostSharp Ultimate, it starts at 10. These thresholds are designed to align with the pricing of various <a href="https://www.postsharp.net/pricing/metalama/enterprise">Metalama Enterprise support plans</a>, as PostSharp subscriptions also include a Metalama license.</p> <p>Details about support levels and their mapping to the number of users can be found here: <a href="https://www.postsharp.net/support/policies/sla">Support Levels</a>.</p> <h2 id="plans-to-release-the-source-code">Plans to release the source code</h2> <p>To further align PostSharp with Metalama’s support model, we plan to release PostSharp’s source code in a private GitHub repository accessible to enterprise customers, with rights to modify and build the product. We expect this to be available by next spring and will keep you updated.</p> <h2 id="postsharp-essentials-improvements">PostSharp Essentials improvements</h2> <p>PostSharp Essentials now offers unlimited support for <code class="language-plaintext highlighter-rouge">async</code> methods, addressing a long-standing limitation.</p> <h2 id="website-updates">Website updates</h2> <p>With Metalama now having its own dedicated website, we’ve streamlined and reorganized <a href="https://www.postsharp.net">https://www.postsharp.net</a> to provide a cleaner, more focused experience.</p> <h2 id="summary">Summary</h2> <p>PostSharp 2025.1 introduces updates to licensing, pricing, and support models, aligning with Metalama’s open-source vision. While no new features or platform updates are included, these changes simplify the product lineup and clarify support levels. Stay tuned for updates on the release of PostSharp’s source code.</p> <p> This article was first published on a <a href="https://blog.postsharp.net">https://blog.postsharp.net</a> under the title <a href="https://blog.postsharp.net/postsharp-2025-1">Announcing PostSharp 2025.1</a>. </p> Fri, 02 May 2025 03:00:01 +0000 Wed, 07 Jan 2026 11:45:59 +0000 https://blog.postsharp.net/postsharp-2025-1 https://blog.postsharp.net/postsharp-2025-1 PostSharp https://blog.postsharp.net/assets/images/2025/2025-05-announcements/postsharp.svg Metalama status update, March 2025 <img src="https://blog.postsharp.net/assets/images/2025/2025-03-status/march-dark.svg" style="width: 100%"/> <p>This month, we released a preview of Metalama 2025.1, marking a significant milestone as the first open-source version of Metalama. Our efforts to complete the open-source transition will continue in April.</p> <h2 id="metalama-20251-open-source-preview">Metalama 2025.1: open-source preview</h2> <p>Earlier this year, we shared our <a href="/metalama-open-source-plans">plans to make Metalama open-source</a>. Since then, we’ve been working hard to bring this vision to life. In March, we released the first preview of Metalama 2025.1, with most components now licensed under MIT. This is a major step toward transitioning Metalama to an open-core business model.</p> <h3 id="whats-left-to-do">What’s left to do</h3> <p>While we’re excited to share this progress with the Metalama community, this isn’t the big announcement yet. There’s still work to be done:</p> <ul> <li>Fixing some bugs</li> <li>Testing on VMs and physical devices</li> <li>Launching a new website</li> <li>Updating documentation and README files</li> <li>Migrating the issue tracker to GitHub</li> <li>Aligning sales pages and processes with the new offering</li> </ul> <h3 id="licensing-notes">Licensing notes</h3> <p>At this stage, licenses for the new business model are not yet available for purchase.</p> <p>Existing Metalama commercial licenses remain compatible with the commercial parts of Metalama 2025.1. However, Metalama Free is not compatible. To use Visual Studio Tools for Metalama, you’ll need either a Metalama license key or to activate Metalama Community. Metalama Community is available for non-commercial users, individuals, companies with up to three users, and contributors to open-source projects.</p> <h3 id="resources-to-get-started">Resources to get started</h3> <p>Here’s how you can explore Metalama 2025.1 today:</p> <ul> <li><a href="https://github.com/metalama/Metalama">Source code on GitHub</a></li> <li><a href="https://www.nuget.org/packages/Metalama.Framework/2025.1.1-preview">Packages on NuGet</a></li> <li><a href="https://www.postsharp.net/downloads/metalama/metalama-2025.1/v2025.1.1-preview/PostSharpMetalama.2025.1.1-preview.vsix">Visual Studio Tooling</a></li> </ul> <h2 id="end-of-support-for-metalama-20242">End of support for Metalama 2024.2</h2> <p>As per our <a href="https://www.postsharp.net/support/policies">support policies</a>, support for Metalama 2024.2 has ended. The only supported version now is Metalama 2025.0.</p> <h2 id="metalama-20250-maintenance-builds">Metalama 2025.0 maintenance builds</h2> <p>We’ve released several maintenance builds for Metalama 2025.0 (<a href="https://github.com/orgs/metalama/discussions/395">2025.0.9</a> and <a href="https://github.com/orgs/metalama/discussions/400">2025.0.10</a>), addressing bugs and integrating the latest stable Roslyn build.</p> <h2 id="updated-roadmap">Updated roadmap</h2> <p>Our focus in April is to finalize the open-source transition. Here’s the updated timeline:</p> <ul> <li><strong>First week of April:</strong> Release Candidate (RC)</li> <li><strong>Late April or Early May:</strong> General Availability (GA)</li> </ul> <p>Thank you for your continued support. Happy meta-programming!</p> <p>-gael</p> <p> This article was first published on a <a href="https://blog.postsharp.net">https://blog.postsharp.net</a> under the title <a href="https://blog.postsharp.net/metalama-status-update-2025-03">Metalama status update, March 2025</a>. </p> Mon, 31 Mar 2025 08:00:01 +0000 Wed, 07 Jan 2026 11:45:59 +0000 https://blog.postsharp.net/metalama-status-update-2025-03 https://blog.postsharp.net/metalama-status-update-2025-03 Status Update https://blog.postsharp.net/assets/images/2025/2025-03-status/march-dark.svg Metalama Status Update, February 2025 <img src="https://blog.postsharp.net/assets/images/2025/2025-02-status/february-dark.svg" style="width: 100%"/> <p>Last month, we shared our exciting <a href="/metalama-open-source-plans">plans to make Metalama open-source</a>, and throughout February, we’ve been hard at work making it happen. While we’ve made significant technical progress, we’re not quite ready to release just yet.</p> <p>On the technical side, we’ve successfully modularized key features in preparation for the transition, allowing us to keep some components proprietary. However, the legal aspects of dual-licensing Metalama are still in progress. It’s a complex process, and we want to ensure everything is done right from the start. This is the main factor delaying the release of our source code and binaries.</p> <h3 id="updated-roadmap">Updated Roadmap</h3> <p>Here’s our revised timeline for the open-source release:</p> <ul> <li><strong>First half of March:</strong> First open-source preview release</li> <li><strong>Second half of March:</strong> Release Candidate (RC)</li> <li><strong>Second half of April:</strong> General Availability (GA)</li> </ul> <p>If the legal process takes longer than expected, we’ll use the extra time to introduce a new feature in the 2025.1 release: <strong>intercepting event invocations</strong>.</p> <p>Between the RC and GA releases, our focus will shift toward supporting infrastructure, including:</p> <ul> <li>Launching a dedicated Metalama website</li> <li>Migrating project and issue management to GitHub</li> <li>Updating our e-shop and CRM systems</li> </ul> <h3 id="stay-tuned">Stay Tuned!</h3> <p>We’re committed to making this transition smooth and impactful. Thank you for your patience and enthusiasm — we’re almost there! Keep an eye out for our updates.</p> <p> This article was first published on a <a href="https://blog.postsharp.net">https://blog.postsharp.net</a> under the title <a href="https://blog.postsharp.net/metalama-status-update-2025-02">Metalama Status Update, February 2025</a>. </p> Thu, 27 Feb 2025 08:00:01 +0000 Wed, 07 Jan 2026 11:45:59 +0000 https://blog.postsharp.net/metalama-status-update-2025-02 https://blog.postsharp.net/metalama-status-update-2025-02 Status Update https://blog.postsharp.net/assets/images/2025/2025-02-status/february-dark.svg Metalama Status Update, January 2025 <img src="https://blog.postsharp.net/assets/images/2025/2025-01-status/january-dark.svg" style="width: 100%"/> <p>As we returned from the winter break, we hit the ground running by launching <strong>Metalama and PostSharp 2025.0</strong>. But that wasn’t all—after careful consideration and experimentation, we’re thrilled to share some groundbreaking news: <strong>Metalama is going open-source</strong>!</p> <h2 id="metalama-and-postsharp-20250-are-generally-available">Metalama and PostSharp 2025.0 are generally available</h2> <p>Following the release of Metalama and PostSharp 2025.0 Release Candidate (RC) in November, we dedicated much of December to squashing bugs. With Metalama maturing steadily, we’ve started addressing long-term, low-priority issues from our backlog.</p> <p>Our first major milestone of the year was deploying <strong>PostSharp and Metalama 2025.0</strong> on January 4th. Here’s what’s new:</p> <ul> <li><strong>Metalama 2025.0</strong>: <ul> <li>Adds support for <strong>C# 13</strong> and <strong>.NET 9</strong>.</li> <li>Introduces significant enhancements to the aspect framework.</li> <li>Delivers substantial performance improvements.<br /> Check out the <a href="/metalama-2025-0-ga">Metalama 2025.0 announcement</a>.</li> </ul> </li> <li><strong>PostSharp 2025.0</strong>: <ul> <li>Adds support for <strong>C# 13</strong>, <strong>.NET 9</strong>, and long paths in projects targeting <strong>.NET Framework</strong>.</li> <li>Improves runtime performance for <code class="language-plaintext highlighter-rouge">WeakEventHandler</code>.</li> <li>Enhances the debugging experience with <strong>Windows PDB files</strong>.<br /> Learn more in the <a href="/postsharp-2025-0-ga">PostSharp 2025.0 announcement</a>.</li> </ul> </li> </ul> <h2 id="metalama-20251-going-open-source"><strong>Metalama 2025.1: going open-source</strong></h2> <p>Earlier this week, we announced that <a href="/metalama-open-source-plans">Metalama 2025.1 will be free and open-source</a>. To ensure the project’s sustainability, we’ll offer commercial IDE tooling, extensions, and support. We fully commit to a cooperative development process, moving everything to GitHub. Metalama will get a dedicated website and GitHub organization, marking its evolution into an independent, community-driven project separate from PostSharp Technologies.</p> <p>Visit the <a href="/metalama-open-source-plans">announcement</a> to learn more about:</p> <ul> <li>What will be free and open-source, and what won’t?</li> <li>Our new commercial offerings.</li> <li>Our updated policies for long-term support.</li> </ul> <p>Your input is invaluable as we implement these changes, so don’t hesitate to share your thoughts while the plans are still being developed.</p> <h2 id="godot--metalama---by-philip-rotter"><strong>Godot + Metalama = ♡, by Philip Rotter</strong></h2> <p><img src="/assets/images/2025/2025-01-godot/filip.jpg" alt="Philip Rotter" class="portrait" /></p> <p>Godot, the incredibly efficient open-source game engine, has gained popularity among developers. While many prefer using C# over GDScript due to its rich ecosystem, exporting C# properties to Godot often involves tedious boilerplate code.</p> <p>In his latest guest post, <a href="/metalama-with-godot">Enhancing Godot Development with Metalama</a>, <a href="https://www.linkedin.com/in/philip-rotter-588a53259/">Philip Rotter</a> demonstrates how Metalama can streamline this process. By leveraging Metalama, Philip eliminates redundant code and makes C# development with Godot both fun and efficient — all through a simple, straightforward aspect.</p> <p>Thank you very much to Philip for this insightful contribution! It will be an invaluable resource for Godot users looking to explore Metalama for the first time.</p> <h2 id="looking-ahead"><strong>Looking ahead</strong></h2> <p>With Metalama’s transition to open-source, 2025 is shaping to be an exciting year! We’re committed to empowering developers with cutting-edge tools to remove code repetition, built together in a collaborative community. Stay tuned for more updates, and don’t forget to share your feedback on <a href="https://www.postsharp.net/">Slack</a> or <a href="https://github.com/orgs/postsharp/discussions/388">GitHub</a> as we continue to evolve and innovate.</p> <p>Happy meta-programming!</p> <p> This article was first published on a <a href="https://blog.postsharp.net">https://blog.postsharp.net</a> under the title <a href="https://blog.postsharp.net/metalama-status-update-2025-01">Metalama Status Update, January 2025</a>. </p> Fri, 31 Jan 2025 08:00:01 +0000 Wed, 07 Jan 2026 11:45:59 +0000 https://blog.postsharp.net/metalama-status-update-2025-01 https://blog.postsharp.net/metalama-status-update-2025-01 Status Update https://blog.postsharp.net/assets/images/2025/2025-01-status/january-dark.svg Enhancing Godot Development with Metalama <img src="https://blog.postsharp.net/assets/images/2025/2025-01-godot/feature.svg" style="width: 100%"/> <p>Godot is an amazing open-source game engine that provides developers with the tools to build games efficiently. While GDScript is Godot’s native language, many developers prefer to use C# for its rich ecosystem and the ability to leverage third-party libraries. One such library is <a href="https://www.postsharp.net/metalama">Metalama</a>, a powerful metaprogramming framework that can streamline repetitive or error-prone tasks.</p> <p>In this article, we’ll explore how to use Metalama to simplify property usage customization in Godot. Specifically, we’ll address a common problem: defining property usage for exported properties in the Godot editor.</p> <blockquote class="guest-author"> <h2 id="about-the-author">About the author</h2> <p><img src="/assets/images/2025/2025-01-godot/filip.jpg" alt="Philip Rotter" /> Philip Rotter is a full-stack developer and passionate game creator with a deep knowledge of diverse game engines and development tools. Currently, he’s focused on building Gradual Warfare, a mobile game developed using the Godot Engine. Gradual Warfare is a future-punk strategy game that blends auto-battle and idle mechanics for an engaging and dynamic player experience. Connect with him on <a href="https://www.linkedin.com/in/philip-rotter-588a53259/">LinkedIn</a>.</p> </blockquote> <h2 id="the-problem-boilerplate-code-for-property-usage">The Problem: Boilerplate Code for Property Usage</h2> <p>The Godot editor allows developers to customize components and resources by overriding the <code class="language-plaintext highlighter-rouge">_ValidateProperty</code> method and setting flags that define property behavior. However, managing property usage flags often results in repetitive and boilerplate-heavy code.</p> <p>For example, imagine you want to create a class with an exported string property that’s only useful in the editor and another property that is hidden in the editor but serialized for runtime use. Here’s how you would traditionally handle this:</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">GlobalClass</span><span class="p">]</span> <span class="p">[</span><span class="n">Tool</span><span class="p">]</span> <span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">ArmyContainer</span> <span class="p">:</span> <span class="n">Resource</span> <span class="p">{</span> <span class="p">[</span><span class="n">Export</span><span class="p">]</span> <span class="k">private</span> <span class="kt">string</span> <span class="n">ExportString</span><span class="p">;</span> <span class="p">[</span><span class="n">Export</span><span class="p">]</span> <span class="k">public</span> <span class="kt">bool</span> <span class="n">ContainsHello</span><span class="p">;</span> <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">_ValidateProperty</span><span class="p">(</span><span class="n">Dictionary</span> <span class="n">property</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">property</span><span class="p">[</span><span class="s">"name"</span><span class="p">].</span><span class="nf">AsStringName</span><span class="p">()</span> <span class="p">==</span> <span class="k">nameof</span><span class="p">(</span><span class="n">ExportString</span><span class="p">))</span> <span class="p">{</span> <span class="n">property</span><span class="p">[</span><span class="s">"usage"</span><span class="p">]</span> <span class="p">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">PropertyUsageFlags</span><span class="p">.</span><span class="n">Editor</span><span class="p">;</span> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">property</span><span class="p">[</span><span class="s">"name"</span><span class="p">].</span><span class="nf">AsStringName</span><span class="p">()</span> <span class="p">==</span> <span class="k">nameof</span><span class="p">(</span><span class="n">ContainsHello</span><span class="p">))</span> <span class="p">{</span> <span class="n">property</span><span class="p">[</span><span class="s">"usage"</span><span class="p">]</span> <span class="p">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">PropertyUsageFlags</span><span class="p">.</span><span class="n">NoEditor</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>This approach works but quickly becomes cumbersome as the number of properties grows. What if we could eliminate this boilerplate and simplify the code?</p> <h2 id="the-solution-attributes-and-metalama">The Solution: Attributes and Metalama</h2> <p>Using Metalama, we can replace the repetitive code with clean, declarative attributes. Here’s what the rewritten class will look like:</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">GlobalClass</span><span class="p">]</span> <span class="p">[</span><span class="n">Tool</span><span class="p">]</span> <span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">ArmyContainer</span> <span class="p">:</span> <span class="n">Resource</span> <span class="p">{</span> <span class="p">[</span><span class="n">Export</span><span class="p">]</span> <span class="p">[</span><span class="n">OnlyInEditor</span><span class="p">]</span> <span class="k">private</span> <span class="kt">string</span> <span class="n">ExportString</span><span class="p">;</span> <span class="p">[</span><span class="n">Export</span><span class="p">]</span> <span class="p">[</span><span class="n">HideInEditor</span><span class="p">]</span> <span class="k">public</span> <span class="kt">bool</span> <span class="n">ContainsHello</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <p>Much cleaner, right? With the help of Metalama, we’ll make these attributes automatically handle property usage without manually overriding <code class="language-plaintext highlighter-rouge">_ValidateProperty</code>.</p> <h2 id="step-1-define-custom-attributes">Step 1: Define Custom Attributes</h2> <p>First, we’ll define the base attribute, <code class="language-plaintext highlighter-rouge">GenPropertyUsageAttribute</code>, which will serve as the foundation for specific attributes like <code class="language-plaintext highlighter-rouge">OnlyInEditor</code> and <code class="language-plaintext highlighter-rouge">HideInEditor</code>.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="nf">AttributeUsage</span><span class="p">(</span><span class="n">AttributeTargets</span><span class="p">.</span><span class="n">Field</span> <span class="p">|</span> <span class="n">AttributeTargets</span><span class="p">.</span><span class="n">Property</span><span class="p">)]</span> <span class="p">[</span><span class="n">RunTimeOrCompileTime</span><span class="p">]</span> <span class="k">public</span> <span class="k">class</span> <span class="nc">GenPropertyUsageAttribute</span> <span class="p">:</span> <span class="n">Attribute</span> <span class="p">{</span> <span class="c1">// Default value: 6 (store and show in editor)</span> <span class="k">public</span> <span class="kt">int</span> <span class="n">PropertyUsageFlags</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="m">6</span><span class="p">;</span> <span class="k">public</span> <span class="nf">GenPropertyUsageAttribute</span><span class="p">()</span> <span class="p">{</span> <span class="p">}</span> <span class="c1">// Constructor to override default PropertyUsageFlags</span> <span class="k">public</span> <span class="nf">GenPropertyUsageAttribute</span><span class="p">(</span><span class="kt">int</span> <span class="n">propertyUsageFlags</span><span class="p">)</span> <span class="p">{</span> <span class="n">PropertyUsageFlags</span> <span class="p">=</span> <span class="n">propertyUsageFlags</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>Now, let’s create two derived attributes for common use cases:</p> <ul> <li><code class="language-plaintext highlighter-rouge">OnlyInEditor</code>: The property is visible in the editor but not stored.</li> <li><code class="language-plaintext highlighter-rouge">HideInEditor</code>: The property is stored but not visible in the editor.</li> </ul> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">RunTimeOrCompileTime</span><span class="p">]</span> <span class="k">public</span> <span class="k">class</span> <span class="nc">OnlyInEditorAttribute</span> <span class="p">:</span> <span class="n">GenPropertyUsageAttribute</span> <span class="p">{</span> <span class="k">public</span> <span class="k">static</span> <span class="k">new</span> <span class="kt">int</span> <span class="n">PropertyUsageFlags</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="m">4</span><span class="p">;</span> <span class="c1">// Editor-only, no storage</span> <span class="k">public</span> <span class="nf">OnlyInEditorAttribute</span><span class="p">()</span> <span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="n">PropertyUsageFlags</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span> <span class="p">}</span> <span class="p">[</span><span class="n">RunTimeOrCompileTime</span><span class="p">]</span> <span class="k">public</span> <span class="k">class</span> <span class="nc">HideInEditorAttribute</span> <span class="p">:</span> <span class="n">GenPropertyUsageAttribute</span> <span class="p">{</span> <span class="k">public</span> <span class="k">new</span> <span class="k">static</span> <span class="kt">int</span> <span class="n">PropertyUsageFlags</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="m">2</span><span class="p">;</span> <span class="c1">// No editor, storage only</span> <span class="k">public</span> <span class="nf">HideInEditorAttribute</span><span class="p">()</span> <span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="n">PropertyUsageFlags</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <h2 id="step-2-create-the-aspect">Step 2: Create the Aspect</h2> <p>Next, we’ll create a Metalama aspect that scans for attributes like <code class="language-plaintext highlighter-rouge">OnlyInEditor</code> and <code class="language-plaintext highlighter-rouge">HideInEditor</code>, then injects logic into the <code class="language-plaintext highlighter-rouge">_ValidateProperty</code> method to apply the appropriate <code class="language-plaintext highlighter-rouge">PropertyUsageFlags</code>.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">GenPropertyUsageTypeAspect</span> <span class="p">:</span> <span class="n">IAspect</span><span class="p">&lt;</span><span class="n">INamedType</span><span class="p">&gt;</span> <span class="p">{</span> <span class="k">public</span> <span class="k">void</span> <span class="nf">BuildEligibility</span><span class="p">(</span><span class="n">IEligibilityBuilder</span><span class="p">&lt;</span><span class="n">INamedType</span><span class="p">&gt;</span> <span class="n">builder</span><span class="p">)</span> <span class="p">{</span> <span class="n">builder</span><span class="p">.</span><span class="nf">MustHaveAttributeOfType</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ToolAttribute</span><span class="p">));</span> <span class="n">builder</span><span class="p">.</span><span class="nf">MustBeConvertibleTo</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">GodotObject</span><span class="p">));</span> <span class="p">}</span> <span class="k">public</span> <span class="k">void</span> <span class="nf">BuildAspect</span><span class="p">(</span><span class="n">IAspectBuilder</span><span class="p">&lt;</span><span class="n">INamedType</span><span class="p">&gt;</span> <span class="n">builder</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Select fields that have the [GenPropertyUsage] attribute.</span> <span class="kt">var</span> <span class="n">fields</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="n">Target</span><span class="p">.</span><span class="n">AllFieldsAndProperties</span> <span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">property</span> <span class="p">=&gt;</span> <span class="n">property</span><span class="p">.</span><span class="n">Attributes</span><span class="p">.</span><span class="nf">OfAttributeType</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">GenPropertyUsageAttribute</span><span class="p">)).</span><span class="nf">Any</span><span class="p">());</span> <span class="c1">// Skip the aspect if we don't have any field.</span> <span class="k">if</span> <span class="p">(!</span><span class="n">fields</span><span class="p">.</span><span class="nf">Any</span><span class="p">())</span> <span class="p">{</span> <span class="n">builder</span><span class="p">.</span><span class="nf">SkipAspect</span><span class="p">();</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="c1">// Introduce a method named _ValidateProperty </span> <span class="c1">// using the template ValidatePropertyTemplate defined below.</span> <span class="n">builder</span><span class="p">.</span><span class="nf">IntroduceMethod</span><span class="p">(</span> <span class="k">nameof</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">_ValidateProperty</span><span class="p">),</span> <span class="n">tags</span><span class="p">:</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Fields</span> <span class="p">=</span> <span class="n">fields</span> <span class="p">},</span> <span class="n">whenExists</span><span class="p">:</span> <span class="n">OverrideStrategy</span><span class="p">.</span><span class="n">Override</span> <span class="p">);</span> <span class="p">}</span> <span class="c1">// Template for the new _ValidateProperty method.</span> <span class="p">[</span><span class="n">Template</span><span class="p">]</span> <span class="k">public</span> <span class="k">void</span> <span class="nf">_ValidateProperty</span><span class="p">(</span><span class="n">Dictionary</span> <span class="n">property</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Call the base method or the hand-written implementation, if any.</span> <span class="n">meta</span><span class="p">.</span><span class="nf">Proceed</span><span class="p">();</span> <span class="kt">var</span> <span class="n">name</span> <span class="p">=</span> <span class="n">property</span><span class="p">[</span><span class="s">"name"</span><span class="p">].</span><span class="nf">AsStringName</span><span class="p">();</span> <span class="c1">// Enumerate all fields identified in the BuildAspect method.</span> <span class="c1">// (This loop executes at build time.)</span> <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">classFieldOrProperty</span> <span class="k">in</span> <span class="p">(</span><span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IFieldOrPropertyOrIndexer</span><span class="p">&gt;)</span><span class="n">meta</span><span class="p">.</span><span class="n">Tags</span><span class="p">[</span><span class="s">"Fields"</span><span class="p">])</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">name</span> <span class="p">==</span> <span class="n">classFieldOrProperty</span><span class="p">.</span><span class="n">Name</span><span class="p">)</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">attribute</span> <span class="p">=</span> <span class="n">classFieldOrProperty</span> <span class="p">.</span><span class="n">Attributes</span> <span class="p">.</span><span class="n">GetConstructedAttributesOfType</span><span class="p">&lt;</span><span class="n">GenPropertyUsageAttribute</span><span class="p">&gt;()</span> <span class="p">.</span><span class="nf">First</span><span class="p">();</span> <span class="n">property</span><span class="p">[</span><span class="s">"usage"</span><span class="p">]</span> <span class="p">=</span> <span class="n">attribute</span><span class="p">.</span><span class="n">PropertyUsageFlags</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <h2 id="step-3-create-the-fabric">Step 3: Create the Fabric</h2> <p>Finally, we’ll use a Metalama fabric to apply our aspect to all eligible classes.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">internal</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">GenPropertyUsageTypeFabric</span> <span class="p">:</span> <span class="n">ProjectFabric</span> <span class="p">{</span> <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">AmendProject</span><span class="p">(</span><span class="n">IProjectAmender</span> <span class="n">amender</span><span class="p">)</span> <span class="p">{</span> <span class="n">amender</span> <span class="p">.</span><span class="nf">SelectDeclarationsWithAttribute</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ToolAttribute</span><span class="p">))</span> <span class="p">.</span><span class="n">OfType</span><span class="p">&lt;</span><span class="n">INamedType</span><span class="p">&gt;()</span> <span class="p">.</span><span class="nf">AddAspectIfEligible</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="k">new</span> <span class="nf">GenPropertyUsageTypeAspect</span><span class="p">());</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <h2 id="testing-the-result">Testing the Result</h2> <p>To test the implementation, you can create a <code class="language-plaintext highlighter-rouge">Tool</code> script in Godot with annotated properties:</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">GlobalClass</span><span class="p">]</span> <span class="p">[</span><span class="n">Tool</span><span class="p">]</span> <span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">ArmyContainer</span> <span class="p">:</span> <span class="n">Resource</span> <span class="p">{</span> <span class="p">[</span><span class="n">Export</span><span class="p">]</span> <span class="p">[</span><span class="n">OnlyInEditor</span><span class="p">]</span> <span class="k">private</span> <span class="kt">string</span> <span class="n">ExportString</span><span class="p">;</span> <span class="p">[</span><span class="n">Export</span><span class="p">]</span> <span class="p">[</span><span class="n">HideInEditor</span><span class="p">]</span> <span class="k">public</span> <span class="kt">bool</span> <span class="n">ContainsHello</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <p>In the Godot editor:</p> <ul> <li><code class="language-plaintext highlighter-rouge">ExportString</code> will be visible but not serialized.</li> <li><code class="language-plaintext highlighter-rouge">ContainsHello</code> will be serialized but not visible in the editor.</li> </ul> <p>This approach eliminates boilerplate code and makes property management much cleaner.</p> <hr /> <h2 id="conclusion">Conclusion</h2> <p>With Metalama, we extended Godot’s functionality by automating the customization of property usage. This approach saves time, reduces boilerplate, and minimizes errors. By leveraging attributes and metaprogramming, we can focus on creating games rather than managing tedious editor logic.</p> <p>Stay tuned for more tutorials on how to enhance Godot development with powerful tools like Metalama. Have fun coding!</p> <p> This article was first published on a <a href="https://blog.postsharp.net">https://blog.postsharp.net</a> under the title <a href="https://blog.postsharp.net/metalama-with-godot">Enhancing Godot Development with Metalama</a>. </p> Wed, 29 Jan 2025 07:00:00 +0000 Wed, 07 Jan 2026 11:45:59 +0000 https://blog.postsharp.net/metalama-with-godot https://blog.postsharp.net/metalama-with-godot featured Guest Article Metalama https://blog.postsharp.net/assets/images/2025/2025-01-godot/feature.svg