﻿<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://community.devexpress.com/feed-stylesheets/rss.xsl" media="screen"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dx="https://www.devexpress.com/" xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>News</title>
    <link>https://community.devexpress.com/Blogs/news/default.aspx</link>
    <description />
    <language>en-US</language>
    <item>
      <guid isPermaLink="false">bd716303-653c-428d-8b8a-a7d998cde032:388288</guid>
      <link>https://community.devexpress.com/Blogs/news/archive/2026/06/02/devexpress-developer-survey-ai-impact-security-accessibility-compliance-upgrade-other-product-experience.aspx</link>
      <category domain="https://community.devexpress.com/Tags/Accessibility">Accessibility</category>
      <category domain="https://community.devexpress.com/Tags/ai">ai</category>
      <category domain="https://community.devexpress.com/Tags/Compliance">Compliance</category>
      <category domain="https://community.devexpress.com/Tags/Featured">Featured</category>
      <category domain="https://community.devexpress.com/Tags/installation">installation</category>
      <category domain="https://community.devexpress.com/Tags/licensing">licensing</category>
      <category domain="https://community.devexpress.com/Tags/security">security</category>
      <category domain="https://community.devexpress.com/Tags/Survey">Survey</category>
      <category domain="https://community.devexpress.com/Tags/upgrade">upgrade</category>
      <category domain="https://community.devexpress.com/Tags/ux">ux</category>
      <title>DevExpress Developer Survey — AI Impact, Regulatory Compliance, Upgrade &amp; General Product Experience</title>
      <description>&lt;p&gt;As always, we thank you for your continued support and for choosing DevExpress for your software development needs.&lt;/p&gt;&lt;p&gt;Below is&amp;nbsp;an important usage survey and we ask that you take a few minutes to submit your feedback to us. Your thoughts/comments will help us shape our future R&amp;amp;D efforts so they better align with your development objectives.&amp;nbsp;&lt;span&gt;The survey should take&amp;nbsp;&lt;/span&gt;&lt;strong&gt;about 10 minutes&lt;/strong&gt;&lt;span&gt;&amp;nbsp;to complete.&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;The focus of this survey is as follows:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;AI-assisted development and its impact on your enterprise&lt;/li&gt;&lt;li&gt;Regulatory compliance requirements in an ever-changing regulatory landscape&lt;/li&gt;&lt;li&gt;Satisfaction with DevExpress product delivery model and licensing&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Your Feedback Matters!&lt;/h2&gt;
&lt;div data-survey-id="67e5b107-c501-4b6b-9d32-727b9d7a3577" data-survey-auth-required="true"&gt;&lt;/div&gt;
&lt;p&gt;&lt;span&gt;Thanks,&lt;/span&gt;&lt;br&gt;&lt;span&gt;Dennis Garavsky&lt;/span&gt;&lt;br&gt;&lt;span&gt;Principal Product Manager&lt;/span&gt;&lt;br&gt;&lt;a href="mailto:dennis@devexpress.com" title="Email me if you have questions or suggestions"&gt;dennis@devexpress.com&lt;/a&gt;&lt;br&gt;&lt;/p&gt;</description>
      <pubDate>Tue, 02 Jun 2026 07:08:00 Z</pubDate>
      <dc:creator>Dennis Garavsky (DevExpress)</dc:creator>
    </item>
    <item>
      <guid isPermaLink="false">bd716303-653c-428d-8b8a-a7d998cde032:388290</guid>
      <link>https://community.devexpress.com/Blogs/news/archive/2026/05/29/application-security-documents-are-untrusted-input.aspx</link>
      <category domain="https://community.devexpress.com/Tags/.NET">.NET</category>
      <category domain="https://community.devexpress.com/Tags/.net+core">.net core</category>
      <category domain="https://community.devexpress.com/Tags/Architecture">Architecture</category>
      <category domain="https://community.devexpress.com/Tags/ASP.NET">ASP.NET</category>
      <category domain="https://community.devexpress.com/Tags/Blazor">Blazor</category>
      <category domain="https://community.devexpress.com/Tags/Office+File+API">Office File API</category>
      <category domain="https://community.devexpress.com/Tags/Reporting">Reporting</category>
      <category domain="https://community.devexpress.com/Tags/security">security</category>
      <category domain="https://community.devexpress.com/Tags/WinForms">WinForms</category>
      <category domain="https://community.devexpress.com/Tags/WPF">WPF</category>
      <category domain="https://community.devexpress.com/Tags/XAF">XAF</category>
      <title>Application Security — Documents Are Untrusted Input</title>
      <description>&lt;h2 id="a-docx-is-a-zip-file"&gt;A .docx is a ZIP file&lt;/h2&gt;
&lt;p&gt;Open a &lt;code&gt;.docx&lt;/code&gt; file in a hex editor and the first two bytes are &lt;code&gt;PK&lt;/code&gt;. Every
modern Office format - &lt;code&gt;.docx&lt;/code&gt;, &lt;code&gt;.xlsx&lt;/code&gt;, &lt;code&gt;.pptx&lt;/code&gt; - is a ZIP archive of XML parts
and embedded resources. PDF is not a ZIP file, but just like Office formats it
is a container. When your code loads any of these file types, some complex work
is done with the content of that container: compressed streams are inflated,
references are resolved, an object graph is materialized.&lt;/p&gt;
&lt;p&gt;Most of us understand a “load document” feature to be a passive read operation:
bytes in, document model out, nothing happens that we didn’t ask for. But
loading is not passive, and the document itself dictates the shape and size of
the process. A document can instruct the loader to allocate gigabytes from a few
kilobytes on disk, to follow a path that climbs out of the extraction directory,
or to decrypt with primitives pulled in by the format specification
implicitly. The document is input, but it must be treated as untrusted input.&lt;/p&gt;
&lt;p&gt;Loading a document implies a security boundary.&lt;/p&gt;
&lt;p&gt;Here are a few examples of known attack vectors used “in the wild” against document loaders:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Decompression bombs” are small archives that inflate to a size which exhausts memory.&lt;/li&gt;
&lt;li&gt;Path traversal (“Zip Slip”) can write outside the intended directory when
extracted carelessly, by using an entry named &lt;code&gt;../../etc/something&lt;/code&gt; or &lt;code&gt;..\..\Windows\System32\something&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Symlink and device-name tricks use entries resolving to absolute paths, or to
reserved Windows names like &lt;code&gt;CON&lt;/code&gt;, &lt;code&gt;NUL&lt;/code&gt;, &lt;code&gt;PRN&lt;/code&gt;, to cause damage when extracted.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="compatible-is-not-secure"&gt;”Compatible” is not “secure”&lt;/h2&gt;
&lt;p&gt;Most applications which load documents can’t easily decide to only support the
latest formats. Of course we know not to assume that old formats are as secure
as new ones, but since support for legacy formats is required, we may believe
that if our loader algorithms are compliant with the latest standards, then we
are secure. Unfortunately, that is not always the case.&lt;/p&gt;
&lt;p&gt;For example, a PDF may be encrypted with AES-128. By name that is a modern
choice, nothing obviously legacy about it. But the PDF standard (ISO 32000-1)
requires AES-128-encrypted PDFs to derive the encryption key with MD5 and to
validate permissions with RC4. Both are long recognized as cryptographically
weak, and neither is permitted under FIPS 140-2, the US government’s
cryptographic standard. PDF readers that support AES-128 encryption need to
support MD5 and RC4, and this means that the code path that loads such documents
is not FIPS-compliant.&lt;/p&gt;
&lt;p&gt;This is what “compatible isn’t secure” actually means: you didn’t knowingly pick
something old, but your choice to support a seemingly current format carries a
hidden legacy dependency. The same is true of Office document protection: the
latest OpenXML formats support SHA-512 hashing, but they also support SHA-1 and
MD5 for legacy reasons. If you support the format, you support the legacy
algorithms too.&lt;/p&gt;
&lt;p&gt;A document format is a specification, and it can mandate approaches that your
application code can’t avoid. Your exposure is inherited from the standards you
choose to support, not introduced by any mistakes you made.&lt;/p&gt;
&lt;p&gt;In the .NET space in particular, the Windows FIPS policy used to be the main
line of defence against this problem. If you tried to load a document that
triggered a non-compliant code path, the runtime would throw an
exception. However, this safety mechanism was never perfect:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On .NET Framework with the Windows FIPS policy enabled, instantiating a
non-validated algorithm threw an exception. However, that exception was a
&lt;code&gt;TargetInvocationException&lt;/code&gt; with a message pointing at a generic non-validated
implementation, and lacking details like the document type or the offending
algorithm.&lt;/li&gt;
&lt;li&gt;On .NET 5 and later, managed FIPS enforcement was largely removed. An MD5/RC4
code path now runs with no error at all. The trap is the transition: code that
threw reliably on .NET Framework can fall silent after a routine upgrade to
.NET 5 or later, with no source change. It is easy to read that silence as the
problem having been fixed, when in fact only the diagnostic has gone, while
the code remains exactly as non -compliant, just quieter about it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This means that any loader code is responsible for auditing the document types
it supports. We can’t rely on the runtime to enforce compliance.&lt;/p&gt;
&lt;h2 id="office-file-api-compliance-and-safety-by-design"&gt;Office &amp;amp; PDF File API: compliance and safety by design&lt;/h2&gt;
&lt;p&gt;The latest &lt;a href="https://www.devexpress.com/products/net/office-file-api/" target="_blank" style="background-color:#ffffff;"&gt;Office &amp;amp; PDF File API&lt;/a&gt; answers both halves of the problem with a single
idea: &lt;strong&gt;compliance and structural safety should be enforced automatically and
early in the pipeline&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;At the cryptographic layer, FIPS enforcement is now explicit. On a FIPS-enforced
Windows system, opening or saving a document that depends on cryptography
prohibited by FIPS (this includes encrypted XLS or DOC files, AES-128 or ARC4
PDFs, OpenXML protection using SHA-1 or MD5 hashes) throws a
&lt;code&gt;DevExpress.Utils.OperatingSystemLevelFipsMode.ComplianceViolationException&lt;/code&gt;
&lt;em&gt;before&lt;/em&gt; processing. We made two design choices to improve upon the .NET
Framework-style handling. First,
the exception derives from &lt;code&gt;System.Security.SecurityException&lt;/code&gt;, so existing
&lt;code&gt;catch (SecurityException)&lt;/code&gt; blocks keep working unchanged. Second, the message
includes actionable details: instead of the runtime’s generic string, our
message tells you which detail of the document you attempted to load was
non-compliant, and we include suggestions for compliance.&lt;/p&gt;
&lt;p&gt;Note that on machines which are not configured with the Windows FIPS policy, or
in non-Windows environments, no cryptography validation is performed. It is
possible to force the same behavior by setting
&lt;code&gt;DevExpress.Utils.OperatingSystemLevelFipsMode.ForcedFipsMode&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;, and
you can use &lt;code&gt;IsEnabled&lt;/code&gt; on the same type to detect whether the policy is
active. Setting &lt;code&gt;ForcedFipsMode&lt;/code&gt; does not change the operating system level
policy.&lt;/p&gt;
&lt;p&gt;At the structural layer, the new &lt;code&gt;SecureZipPolicy&lt;/code&gt; applies to both the low-level
data engine (&lt;code&gt;DevExpress.Utils.Zip&lt;/code&gt;) and the high-level API
(&lt;code&gt;DevExpress.Compression.ZipArchive&lt;/code&gt;). It enforces resource limits with sensible
defaults, such as maximum entry count, per-entry and total uncompressed size,
per-entry and total compression ratio to guard against “decompression bombs”, as
well as path-nesting depth. It blocks the structural attacks mentioned earlier:
path traversal, absolute paths, control characters, reserved device names,
symlinks. The write-time encryption default also changes from the old
&lt;code&gt;EncryptionType.PkZip&lt;/code&gt; to AES-256.&lt;/p&gt;
&lt;p&gt;The structural enforcement through &lt;code&gt;SecureZipPolicy&lt;/code&gt; applies to all ZIP
processing and is not tied to the FIPS policy. But on systems that do not have
FIPS enabled, a call to &lt;code&gt;SecureZipPolicy.SetEncryptionPolicy(...)&lt;/code&gt; with either
&lt;code&gt;AesRequired&lt;/code&gt; or &lt;code&gt;FipsStrict&lt;/code&gt; (the latter disallows any unknown encryption types
on read) enables the encryption policies regardless of any OS-level
configuration.&lt;/p&gt;
&lt;h2 id="some-of-these-changes-may-be-breaking"&gt;Some of these changes may be “breaking”&lt;/h2&gt;
&lt;p&gt;If you process documents on FIPS-enforced systems, code that previously ran on
.NET 5 or later may now throw an exception. We have published detailed guidance
for existing code, &lt;a href="https://supportcenter.devexpress.com/ticket/details/t1327031/office-pdf-file-api-fips-enforcement-for-encrypted-doc-xls-and-pdf-documents" rel="nofollow noreferrer" target="_blank"&gt;Breaking Change T1327031 for the Office and PDF File
API&lt;/a&gt;
and &lt;a href="https://supportcenter.devexpress.com/ticket/details/t1325920/new-zip-security-policy-has-been-applied-to-both-our-low-level-data-engine-devexpress" rel="nofollow noreferrer" target="_blank"&gt;Breaking Change T1325920 for the new Zip Security
Policy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It is important to point out that these changes are only “breaking” in the sense
that they change behavior for existing implementations. They make your code
safer (very directly so in the case of the new Zip security policy), and offer
improved discoverability and auditability of violations for FIPS compliance.&lt;/p&gt;
&lt;p&gt;Without repeating the details of the guides, it is possible to adjust some of
the defaults to restore old behavior, but also to accommodate your
requirements. For example, the Zip policy has tunable parameters for resource
protection.&lt;/p&gt;
&lt;p&gt;We recommend that you take the opportunity to review your document processing
code and consider whether you can migrate to more secure formats. You can use
the new observable violations to identify documents that are currently being
processed but would not be compliant with the new policies, and then make
informed decisions.&lt;/p&gt;&lt;p&gt;&lt;span&gt;See also:&amp;nbsp;&lt;/span&gt;&lt;a href="https://community.devexpress.com/Blogs/news/archive/2026/04/17/application-security-stronger-hashes-and-safer-passwords.aspx"&gt;Application Security — Stronger Hashes and Safer Passwords&lt;/a&gt;&lt;span&gt;.&lt;/span&gt;&lt;br&gt;&lt;/p&gt;
&lt;h2 id="compatibility-and-security"&gt;Compatibility and security&lt;/h2&gt;
&lt;p&gt;A common perception is that security and compatibility are always in tension. We
should state up front that this is not generally true. The new &lt;a href="https://www.devexpress.com/products/net/office-file-api/" target="_blank"&gt;Office &amp;amp; PDF File API&lt;/a&gt;
is an example of a case where the compliant choice and the convenient choice are
the same, and the new enforcement simply makes that alignment visible. For many
applications, there is no meaningful trade-off between security and
compatibility.&lt;/p&gt;
&lt;p&gt;The real conflict between security and compatibility is mostly at the legacy
surface area. Sticking to documents as the main topic of this article, that
legacy surface area can be large if you need to support old formats and old
storage standards, but it can be small if you can migrate to current formats.&lt;/p&gt;
&lt;p&gt;There are two recommendations for navigation of this tension.&lt;/p&gt;
&lt;p&gt;First, if you can use current formats, do. Migrating encrypted XLS to XLSX, DOC
to DOCX and AES-128/ARC4 PDFs to AES-256 (Revision 6) is an easy and cheap
path - speaking from the purely technical perspective of course, while
organizational and regulatory constraints may be more complex, and only you can
judge the practical complexity of migration in your environment.&lt;/p&gt;
&lt;p&gt;If legacy formats are genuinely unavoidable, then treat those documents
explicitly as untrusted input and wrap them accordingly: you now get resource
limits by default, and you can consider separating your loading or conversion
logic out to a standalone process that makes it possible to apply OS limits on
memory use or prevent network access - bearing in mind that any loading method
still parses the document, so the point of a separate process is to contain that
parse, not to avoid it.&lt;/p&gt;
&lt;p&gt;Depending on the exposure your project has to unverified input, you will find
your own balance of “defense in depth” measures, but it is important to make
active decisions about these assessments. Monitoring for violations is easy with
the new policies, and the &lt;code&gt;ResourceLimitViolation&lt;/code&gt; and &lt;code&gt;TrustBoundaryViolation&lt;/code&gt;
events exist precisely so that you gain auditability that matters particularly
in regulated, enterprise, and government environments.&lt;/p&gt;

&lt;h2&gt;Your Feedback Matters!&lt;/h2&gt;
&lt;div data-survey-id="b31c0c9e-b420-4b2b-9501-2a16d14dd7af" data-survey-auth-required="false"&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 29 May 2026 07:04:00 Z</pubDate>
      <dc:creator>Oliver Sturm (DevExpress)</dc:creator>
    </item>
    <item>
      <guid isPermaLink="false">bd716303-653c-428d-8b8a-a7d998cde032:388287</guid>
      <link>https://community.devexpress.com/Blogs/news/archive/2026/05/07/sboms-for-cra-compliance-in-devexpress-based-apps-preview-now-open.aspx</link>
      <category domain="https://community.devexpress.com/Tags/.NET">.NET</category>
      <category domain="https://community.devexpress.com/Tags/.net+core">.net core</category>
      <category domain="https://community.devexpress.com/Tags/CRA">CRA</category>
      <category domain="https://community.devexpress.com/Tags/Featured">Featured</category>
      <category domain="https://community.devexpress.com/Tags/JS">JS</category>
      <category domain="https://community.devexpress.com/Tags/npm">npm</category>
      <category domain="https://community.devexpress.com/Tags/NuGet">NuGet</category>
      <category domain="https://community.devexpress.com/Tags/SBOM">SBOM</category>
      <category domain="https://community.devexpress.com/Tags/security">security</category>
      <category domain="https://community.devexpress.com/Tags/VCL">VCL</category>
      <title>SBOMs for CRA Compliance in DevExpress-Based Apps — Preview Now Open</title>
      <description>&lt;p&gt;If you ship apps to customers in the EU, the Cyber Resilience Act (CRA) will require a Software Bill of Materials&amp;nbsp;(SBOM) as part of your conformity documentation. SBOM generation and CRA compliance are top priorities for DevExpress, and CycloneDX SBOM files for our .NET NuGet packages are now available as a preview. We are looking for feedback to help us refine our solution before a broader release.&lt;/p&gt;
&lt;h2 id="why-this-matters"&gt;Why This Matters&lt;/h2&gt;
&lt;p&gt;Regulatory expectations around software supply chain transparency have moved from emerging practice to a baseline requirement over the past four years:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2021&lt;/strong&gt; — SBOM became a key requirement of the &lt;a href="https://www.whitehouse.gov/briefing-room/presidential-actions/2021/05/12/executive-order-on-improving-the-nations-cybersecurity/"&gt;US Executive Order 14028 on Improving the Nation&amp;#39;s Cybersecurity&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2022&lt;/strong&gt; — Microsoft open-sourced its &lt;a href="https://devblogs.microsoft.com/engineering-at-microsoft/microsoft-open-sources-software-bill-of-materials-sbom-generation-tool/"&gt;SBOM generation tool&lt;/a&gt;, signaling SBOM as a standard part of the build pipeline.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2024&lt;/strong&gt; — Germany&amp;#39;s &lt;a href="https://www.bsi.bund.de/SharedDocs/Downloads/EN/BSI/Publications/TechGuidelines/TR03183/BSI-TR-03183-2_v2_1_0.pdf"&gt;BSI TR-03183 Part 2&lt;/a&gt; made SBOM delivery mandatory for products in scope. The &lt;a href="https://en.wikipedia.org/wiki/Cyber_Resilience_Act"&gt;EU Cyber Resilience Act (CRA)&lt;/a&gt; adopted the same requirement and entered into force on December 10, 2024, with a three-year transition period. Manufacturers selling digital products in the EU must produce and maintain SBOMs for conformity assessment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026&lt;/strong&gt; — CRA vulnerability reporting obligations apply from September 11, 2026, ahead of full applicability on December 11, 2027.&lt;/li&gt;
&lt;/ul&gt;
&lt;img src="https://community.devexpress.com/blogs/news/2026/sbom-announcement/sbom-timeline.png" alt="sbom-timeline"&gt;
&lt;p&gt;Under the CRA, SBOM obligation falls on the manufacturer of the finished product. You can run an SBOM generation tool against your project and assemble most of what you need. But tools that read package manifests cannot reliably see bundled NPM assets, statically-linked code, or license attribution for third-party components embedded at build time. A vendor-signed SBOM can fill these gaps and serve as stronger evidence when compared to tool-derived data. Our goal is to provide SBOMs that fit cleanly into workflows you already use.&lt;/p&gt;
&lt;h2 id="what-s-available-today-preview-"&gt;What&amp;#39;s Available Today (Preview)&lt;/h2&gt;
&lt;p&gt;DevExpress publishes digitally-signed CycloneDX 1.6 SBOM files for our .NET NuGet packages. Each SBOM is updated with every build. These files use our production format and signing pipeline — &amp;quot;preview&amp;quot; status reflects ongoing metadata alignment with &lt;a href="https://www.cisa.gov/sites/default/files/2025-08/2025_CISA_SBOM_Minimum_Elements.pdf"&gt;NTIA Minimum Elements&lt;/a&gt; and &lt;a href="https://www.bsi.bund.de/SharedDocs/Downloads/EN/BSI/Publications/TechGuidelines/TR03183/BSI-TR-03183-2_v2_1_0.pdf"&gt;BSI TR-03183&lt;/a&gt;, not file quality.&lt;/p&gt;
&lt;p&gt;Each SBOM:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lists first-party and third-party dependencies, including transitive dependencies.&lt;/li&gt;
&lt;li&gt;Includes a dependency graph for the package it describes.&lt;/li&gt;
&lt;li&gt;Lists corresponding NPM packages and their transitive dependencies when DevExpress .NET packages bundle client-side NPM assets.&lt;/li&gt;
&lt;li&gt;Marks NPM devDependencies (used during development but not shipped) with &lt;code&gt;&amp;quot;scope&amp;quot;: &amp;quot;excluded&amp;quot;&lt;/code&gt; for transparency.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These files can be consumed by standard SBOM analysis tools — including Dependency-Track, Trivy, and Grype.&lt;/p&gt;
&lt;h3 id="current-scope"&gt;Current Scope&lt;/h3&gt;
&lt;p&gt;This first release covers DevExpress .NET product packages (Blazor, WinForms, WPF, ASP.NET Core, Web Forms, MVC, and shared component libraries) published on NuGet.org for our current shipping version (v25.2.6). It does not yet cover VCL or DevExtreme product libraries, installers, demos, packages from our private NuGet feed, standalone assembly-level SBOMs, or earlier package versions. We are starting with this narrow scope so we can refine output based on customer requirements before broadening coverage.&lt;/p&gt;
&lt;div class="Note"&gt;For complete technical details — including known limitations, format specifics, and step-by-step guidance for Dependency-Track, Trivy, and Grype — see our &lt;a href="https://supportcenter.devexpress.com/ticket/details/t1312026/software-bill-of-materials-sbom-for-devexpress-net-assemblies-nuget-packages-javascript"&gt;SBOM discussion thread&lt;/a&gt;.&lt;/div&gt;
&lt;h2 id="your-feedback-matters"&gt;Your Feedback Matters&lt;/h2&gt;
&lt;p&gt;Our SBOM preview is now open to additional participants — particularly developers working on compliance, supply chain security, or vulnerability management for applications built with DevExpress components.&lt;/p&gt;
&lt;p&gt;If you are willing to test our SBOM files in your existing tooling and share what works (and what does not), please complete the survey below. After you submit, our team contacts you with download access and next steps. Survey participants also get a direct line to the product team. If you would prefer to discuss specifics outside the survey, you can also &lt;a href="https://www.devexpress.com/ask"&gt;open a private support ticket&lt;/a&gt;.&lt;/p&gt;
&lt;div data-survey-id="8bfc2c72-365b-4638-b3c5-c89875a66d49" data-survey-auth-required="true"&gt;&lt;/div&gt;</description>
      <pubDate>Thu, 07 May 2026 10:10:00 Z</pubDate>
      <dc:creator>Alex Chuev (DevExpress)</dc:creator>
      <dx:excerpt>If you ship apps to customers in the EU, the Cyber Resilience Act (CRA) will require an SBOM as part of your conformity documentation. SBOM generation and CRA compliance are top priorities for DevExpress, and CycloneDX SBOM files for our .NET NuGet packages are now available as a preview</dx:excerpt>
    </item>
    <item>
      <guid isPermaLink="false">bd716303-653c-428d-8b8a-a7d998cde032:388286</guid>
      <link>https://community.devexpress.com/Blogs/news/archive/2026/04/27/microsoft-build-2026-is-coming.aspx</link>
      <category domain="https://community.devexpress.com/Tags/build">build</category>
      <title>Microsoft Build 2026 is coming!</title>
      <description>&lt;p&gt;...And we shall be there! Not in Seattle this year, but, for a change, in San Francisco. To be more accurate, Microsoft Build will be&amp;nbsp;at&amp;nbsp;&lt;span style="color:#000000;"&gt;Fort Mason Center in San Francisco, CA. for two full days, June 2-3. As is usual,&amp;nbsp;sessions will also be broadcast&amp;nbsp;online.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;The main emphasis of Microsoft Build 2026 is going to be&amp;nbsp;AI. Not only how to use AI workflows and agents to write code and applications, but also how to provide AI capabilities to end-users to help them&amp;nbsp;use&amp;nbsp;those apps.&amp;nbsp;Naturally sessions will also cover how developers &amp;quot;supervise&amp;quot; output from AI agents&amp;nbsp;through testing, checking outputs for security, applicability, and so on. For more details on the sessions that will occur at Build, please follow &lt;a href="https://build.microsoft.com/en-US/home" title="Microsoft Build 2026 website"&gt;this link&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;span style="color:#000000;"&gt;Like every year, DevExpress will have a booth in the Partner Hub, and we will be there to chat to attendees about what&amp;#39;s happening&amp;nbsp;with our next major releases coming up in late June, as well as how we&amp;#39;re supporting&amp;nbsp;the topics highlighted&amp;nbsp;in the Build sessions. We&amp;#39;ll talk about how we&amp;#39;re providing support for AI agents&amp;nbsp;when writing apps with our controls, as well as how we&amp;#39;re providing AI capabilities for end-users of the apps that use those&amp;nbsp;controls.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#000000;"&gt;We look forward to seeing you at our booth if you&amp;#39;re going to Microsoft Build 2026. Do&amp;nbsp;please stop by and say hello!&lt;/span&gt;&lt;/p&gt;</description>
      <pubDate>Mon, 27 Apr 2026 15:10:00 Z</pubDate>
      <dc:creator>Julian Bucknall (DevExpress)</dc:creator>
    </item>
    <item>
      <guid isPermaLink="false">bd716303-653c-428d-8b8a-a7d998cde032:388285</guid>
      <link>https://community.devexpress.com/Blogs/news/archive/2026/04/24/application-security-project-dependency-version-bumps-demystified-modern-security-realities-in-net-nuget-ecosystem.aspx</link>
      <category domain="https://community.devexpress.com/Tags/.NET">.NET</category>
      <category domain="https://community.devexpress.com/Tags/.net+core">.net core</category>
      <category domain="https://community.devexpress.com/Tags/JS">JS</category>
      <category domain="https://community.devexpress.com/Tags/npm">npm</category>
      <category domain="https://community.devexpress.com/Tags/NuGet">NuGet</category>
      <category domain="https://community.devexpress.com/Tags/security">security</category>
      <title>Application Security — Project Dependency "Version Bumps" Demystified or Modern Security Realities in .NET / NuGet Ecosystem</title>
      <description>&lt;p&gt;In this post, I want to show you how to effectively upgrade vulnerable third-party dependencies in your projects, highlight .NET industry best practices, and also clarify how DevExpress helps you mitigate security-related risks in general. For illustration purposes, I will use a System.Security.Cryptography.Xml-related security advisory, which Microsoft published in the GitHub Advisory database &lt;a href="https://github.com/advisories/GHSA-w3x6-4m5h-cxqf" target="_blank"&gt;last week&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You probably already know about this report from NuGet, Visual Studio, or &lt;a href="https://supportcenter.devexpress.com/ticket/details/t1326802/vulnerable-system-security-cryptography-xml-nuget-package-versions-10-0-0-10-0-5-9-0-0-9" target="_blank"&gt;DevExpress Support Center&lt;/a&gt;. And if not, it&amp;#39;s important to note that &lt;b&gt;such reports impact every NuGet package, which has direct or transitive dependencies on the highlighted package version&lt;/b&gt; (it&amp;#39;s not specific to DevExpress directly). Ultimately, even if such external advisories do not originate from DevExpress, they may impact DevExpress packages and DevExpress customers via a chain of system or third-party sub-dependencies. Hence, it&amp;#39;s still our responsibility as a component vendor to inform our customers, improve transparency and awareness of the best practices, update problematic dependencies of affected DevExpress packages in our new releases.&lt;/p&gt;

&lt;img src="https://community.devexpress.com/blogs/news/ghsa-fixed-versions.png" alt="" style="width:2009px;height:711px;border-width:1px;border-color:#c0c0c0;border-style:solid;"&gt;

&lt;p&gt;As a result of this System.Security.Cryptography.Xml advisory, you might see warnings in your Solution Explorer, NuGet Package Manager or just build output (example for .NET 8 projects). Since we also build .NET projects and use the same development tools daily, we knew about this new report right after its publication in the GitHub Advisory database on April 13-14th 2026 &lt;strong&gt;(much like you, other vendors or anyone else)&lt;/strong&gt;. Fortunately for all, a general fix (upgrade to the latest package version) is also available for all affected DevExpress and other vendor packages that were &lt;strong&gt;released prior to publishing such advisories&lt;/strong&gt; (for example, DevExpress v25.2.6 released on 07 Apr 2026 - a week before this particular report).&lt;/p&gt;

&lt;div class="Note"&gt;warning NU1901: Package &amp;#39;System.Security.Cryptography.Xml&amp;#39; 8.0.2 has a known low severity vulnerability, &lt;a href="https://github.com/advisories/GHSA-w3x6-4m5h-cxqf" rel="nofollow"&gt;https://github.com/advisories/GHSA-w3x6-4m5h-cxqf&lt;/a&gt;&lt;br&gt;DevExpress.Blazor imports the transitive package of System.Security.Cryptography.Xml&lt;/div&gt;

&lt;img src="https://community.devexpress.com/blogs/news/image_9.png" alt=""&gt;

&lt;h2&gt;How to Fix This&lt;/h2&gt;
&lt;h3&gt;General Fix Idea (Applicable to All Methods)&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The beauty of such simple &amp;quot;version bump&amp;quot; vulnerabilities is that you can easily fix it yourself immediately - without awaiting anyone (vendors, new package versions, etc).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can bump the version right in your project for affected third-party dependencies (such as Microsoft .NET System.XXX or others), as described in the &amp;quot;&lt;em&gt;How do I fix the issue?&lt;/em&gt;&amp;quot; section of the official advisory. Anyone can apply this fix at their convenience (even &amp;quot;within hours&amp;quot; of publication of the original security advisory in the CVE / GHSA database), because in this instance it&amp;#39;s literally one line of code in one or a few places only.&lt;/p&gt;

&lt;img src="https://community.devexpress.com/blogs/news/ghsa-how-to-fix.png" alt="" style="width:2258px;height:1646px;border-width:1px;border-color:#c0c0c0;border-style:solid;"&gt;

&lt;p&gt;I also want to emphasize that when a vulnerability occur in a system or core .NET library, many other dependent system, .NET BCL, and vendor libraries are impacted. For example, System.Security.Cryptography.Xml is used by System.ServiceModel.Http, System.ServiceModel.Primitives, System.ServiceModel and others. They are also used directly or indirectly in a dozen more packages - all are often used in many apps of even medium complexity (I am not even talking about complex apps). You will have to update those dependencies anyway, regardless DevExpress or any other impacted package vendor/third-party.&lt;/p&gt;

&lt;p&gt;Notwithstanding the negative effects of dealing with a vulnerability, NuGet and its best practices such as Central Package Management (CPM) exist in the development world - all to deal with such incidents quickly and to address modern realities effectively.

&lt;/p&gt;&lt;h3&gt;Method #1: You Have a Few Projects Only or Are NOT Using Central Package Management (CPM)&lt;/h3&gt;

&lt;div class="Note"&gt;&lt;strong&gt;Applicability&lt;/strong&gt;: Simple applications (~1-3-5 projects in your solution), no CPM yet.&lt;br&gt;&lt;strong&gt;Urgency&lt;/strong&gt;: High (apply immediately).&lt;br&gt;&lt;strong&gt;Complexity&lt;/strong&gt;: Medium - Temporarily copy and maintain one code line in &lt;strong&gt;X&lt;/strong&gt; files (the number of your projects).&lt;br&gt;&lt;strong&gt;Risks&lt;/strong&gt;: Low.&lt;/div&gt;

&lt;p&gt;The standard Microsoft solution is to add a direct NuGet package reference (&lt;strong&gt;System.Security.Cryptography.Xml&lt;/strong&gt; in this case, but it can be another third-party package) to your required projects (CSPROJ/VBPROJ) and set its &lt;strong&gt;VersionOverride&lt;/strong&gt; property to the patched version from the advisory (for example, &lt;strong&gt;8.0.3&lt;/strong&gt; for .NET 8):&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;.NET 8&lt;/strong&gt;: &amp;lt;PackageReference Include=&amp;quot;System.Security.Cryptography.Xml&amp;quot; VersionOverride=&amp;quot;8.0.3&amp;quot; /&amp;gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;.NET 9&lt;/strong&gt;: &amp;lt;PackageReference Include=&amp;quot;System.Security.Cryptography.Xml&amp;quot; VersionOverride=&amp;quot;9.0.15&amp;quot; /&amp;gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;.NET 10&lt;/strong&gt;: &amp;lt;PackageReference Include=&amp;quot;System.Security.Cryptography.Xml&amp;quot; VersionOverride=&amp;quot;10.0.6&amp;quot; /&amp;gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, this is a one-line solution, which you can copy into required projects where problematic direct or transitive dependencies were detected. In my example, I copied it into 2 projects only (so, 2 code lines in total to maintain &lt;strong&gt;temporarily&lt;/strong&gt;).&lt;/p&gt;

&lt;h3&gt;Method #2: You Have Multiple Projects or Are Using Central Package Management (CPM)&lt;/h3&gt;

&lt;div class="Note"&gt;&lt;strong&gt;Applicability&lt;/strong&gt;: Medium to complex applications (more than 5 projects in your solution), CPM configured.&lt;br&gt;&lt;strong&gt;Urgency&lt;/strong&gt;: High (apply immediately).&lt;br&gt;&lt;strong&gt;Complexity&lt;/strong&gt;: Low - Temporarily copy and maintain one code line in one file.&lt;br&gt;&lt;strong&gt;Risks&lt;/strong&gt;: Low.&lt;br&gt;&lt;/div&gt;

&lt;p&gt;If you have too many projects so that even the one-line solution is not practical to copy/maintain, then you must seriously consider using &lt;a href="https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management"&gt;Central Package Management (CPM)&lt;/a&gt;. &lt;strong&gt;CPM is the best or recommended development practice regardless this vulnerability discussion anyway.&lt;/strong&gt;&lt;/p&gt;

&lt;img src="https://community.devexpress.com/blogs/news/image_8.png" alt="" style="width:3524px;height:1594px;border-width:1px;border-color:#c0c0c0;border-style:solid;"&gt;

&lt;p&gt;Once you configure CPM for your solution, you can add a global package reference to your Directory.Packages.props file:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;.NET 8&lt;/strong&gt;: &amp;lt;GlobalPackageReference Include=&amp;quot;System.Security.Cryptography.Xml&amp;quot; Version=&amp;quot;8.0.3&amp;quot; /&amp;gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;.NET 9&lt;/strong&gt;: &amp;lt;GlobalPackageReference Include=&amp;quot;System.Security.Cryptography.Xml&amp;quot; Version=&amp;quot;9.0.15&amp;quot; /&amp;gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;.NET 10&lt;/strong&gt;: &amp;lt;GlobalPackageReference Include=&amp;quot;System.Security.Cryptography.Xml&amp;quot; Version=&amp;quot;10.0.6&amp;quot; /&amp;gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regardless how many projects you have in your .NET solution (5, 100, 200, etc.), this is always a one-line solution to maintain &lt;strong&gt;temporarily&lt;/strong&gt; - that is the beauty of CPM in action.&lt;/p&gt;

&lt;img src="https://community.devexpress.com/blogs/news/image_6.png" alt="" style="width:558px;height:507px;"&gt;

&lt;p&gt;CPM is nowadays also super-fast to add to your non-CPM solution with AI assistants. If you already maintain a Directory.Packages.props, replacing &amp;quot;PackageVersion&amp;quot; with &amp;quot;GlobalPackageReference&amp;quot; is fast too with or without AI.&lt;/p&gt;

&lt;img src="https://community.devexpress.com/blogs/news/image_5.png" alt=""&gt;

&lt;h3 id="additional-information"&gt;Method #3: Await &amp;amp; Install a New/Fixed DevExpress Build&lt;/h3&gt;

&lt;div class="Note"&gt;&lt;strong&gt;Applicability&lt;/strong&gt;: Applications of any complexity, with or without CPM.&lt;br&gt;&lt;strong&gt;Urgency&lt;/strong&gt;: Low (await a few weeks).&lt;br&gt;&lt;strong&gt;Complexity&lt;/strong&gt;: Medium - Download a new version and re-test your application completely.&lt;br&gt;&lt;strong&gt;Risks&lt;/strong&gt;: Low - for the official maintenance update; High - for a hot-fix/intermediate build.&lt;/div&gt;

&lt;p&gt;Affected DevExpress packages are typically updated in the next minor release according to our &lt;a href="https://docs.devexpress.com/GeneralInformation/403365/security/security?utm_source=SupportCenter&amp;amp;utm_medium=website&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1326802#security-advisories-and-product-update-process"&gt;Security Advisories and Product Update Process&lt;/a&gt;. This usually takes a few weeks or so.&lt;/p&gt;

&lt;p&gt;If you wish, you can request a hot-fix/intermediate build as well. For example, for this particular System.Security.Cryptography.Xml vulnerability we updated our packages and published a fixed night build at &lt;a href="https://downloads.devexpress.com/HotFixes/DXP/v25.2" style="color:#337ab7;"&gt;https://downloads.devexpress.com/HotFixes/DXP/v25.2&lt;/a&gt;. NOTE: &lt;a href="https://www.devexpress.com/support/eulas/hotfix-policy.xml" style="color:#337ab7;"&gt;review our hot-fix policy first&lt;/a&gt; before applying.
&lt;/p&gt;

&lt;h2&gt;Frequently Asked Questions (FAQ)&lt;/h2&gt;

&lt;h3&gt;Does DevExpress release builds when it already &amp;quot;knows&amp;quot; about a vulnerability such as System.Security.Cryptography.Xml 8.0.2?&lt;/h3&gt;

&lt;p&gt;No. In this instance, DevExpress v25.2.6 was released on 07 Apr 2026, many days before the aforementioned vulnerability was even published/known to the world. &lt;/p&gt;

&lt;p&gt;DevExpress uses a multi-layered scanning strategy for every PR (code repositories and container images are continuously and automatically scanned for vulnerabilities during the CI/CD process) &lt;strong&gt;prior to release&lt;/strong&gt;. This includes Static Application Security Testing (SAST) for product source code, Software Composition Analysis (SCA) for vulnerable third-party libraries/license compliance, antiviral software installation and artifact scanning. High-risk vulnerabilities trigger an automatic &amp;#39;Build Fail&amp;#39;. DevExpress employs a combination of commercial and internally managed security tools (including, but not limited to Veracode, Dependabot, CodeQL, NuGet Audit, VirusTotal, etc).&lt;/p&gt;

&lt;p&gt;For more information, please review &lt;a href="https://www.devexpress.com/support/information-security.xml" style="color:#337ab7;"&gt;Information Security&lt;/a&gt; and &lt;a href="https://docs.devexpress.com/GeneralInformation/403365/security/security" style="color:#337ab7;"&gt;Security - What You Need to Know&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;How often similar security advisories for system/core or popular 3rd-party packages are reported?&lt;/h3&gt;

&lt;p&gt;Quite many every day - it&amp;#39;s best to estimate it for yourself at &lt;a href="https://github.com/advisories" target="_blank"&gt;https://github.com/advisories&lt;/a&gt; (filter by NuGet, NPM, or other keywords). This is also not the first and not the last vulnerability in a system/core library. For example, 3 security advisories were published for System.Security.Cryptography.Xml alone in less than 2 years. And I am not even referring to others in popular SQL Client, JSON, OData, and other libraries with even more dependencies.&lt;/p&gt;

&lt;p&gt;To better understand the situation, let&amp;#39;s make a thought experiment: imagine that a vendor started publishing new official builds in response to each and every security advisory immediately. For this (in theory), one would need the previous official build, bump the affected NuGet package version (such as System.Security.Cryptography.Xml), re-build, re-run automatic tests and security checks, and publish a new official build. As a result of this experiment, customers would need to deal with 3-5 new minors a week. That rough number is only considering the current CVE/GHSA update rate for .NET - for JS/NPM it would be even more frequent. As you may understand, not many customers or businesses would want such an update carousel.&lt;/p&gt;

&lt;img src="https://community.devexpress.com/blogs/news/image_4.png" alt="" style="border-width:1px;border-color:#c0c0c0;border-style:solid;"&gt;

&lt;h3&gt;How often DevExpress &amp;quot;bumps versions&amp;quot; of their .NET packages internally in response to security advisories for external NuGet packages?&lt;/h3&gt;

&lt;p&gt;Multiple times every month or so. To give you a full picture, DevExpress v25.2 .NET packages depend on over 150+ system/core .NET packages (based on our &amp;quot;c:\Program Files\DevExpress 25.2\Components\Sources\Directory.Packages.props&amp;quot; file or our public &lt;a href="https://supportcenter.devexpress.com/ticket/details/t1312026/software-bill-of-materials-sbom-for-devexpress-net-assemblies-nuget-packages-javascript" target="_blank"&gt;SBOM artifacts&lt;/a&gt;, which you can check for yourself). Our .NET packages often include our JS packages as assets, these JS packages depend on external JS/NPM packages, and so on - you got the idea or the high chances of a &amp;quot;version bump&amp;quot; at such a scale.&lt;/p&gt;

&lt;p&gt;Good news is that we heavily rely on CPM, so this &amp;quot;version bumping&amp;quot; itself is now a mechanical routine - it just takes time and discipline from our product teams. This is basically what every developer of any serious or complex application/solution is doing nowadays, because security matters.&lt;/p&gt;

&lt;h3&gt;Why does not DevExpress release a new/fixed build within hours after a security advisory is published?&lt;/h3&gt;

&lt;p&gt;As noted in Method #3, we follow our &lt;a href="https://docs.devexpress.com/GeneralInformation/403365/security/security#security-advisories-and-product-update-process" style="color:#337ab7;"&gt;Security Advisories and Product Update Process&lt;/a&gt; and update affected DevExpress packages  in the next minor release (in a few weeks or so &lt;strong&gt;on purpose&lt;/strong&gt;). All our builds must pass standard testing procedures. We do our best to test our software and it takes time (for example, we intentionally did not release v25.2.7 &amp;quot;within hours&amp;quot;). We simply do not want our customers rely on poorly tested software (and potentially experience bigger issues with the upgrade). &lt;/p&gt;

&lt;p&gt;Fortunately, the current release cadence suits the majority of our customers and proved itself over the years well. In urgent cases, customers can either apply a one-line solution in their projects or request a hot-fix/intermediate build. That is also why Microsoft has Patch Tuesday &lt;strong style="color:#333333;"&gt;monthly &lt;/strong&gt;and NOT &amp;quot;hourly&amp;quot;, and many other vendors follow similar security and testing protocols. Otherwise, it would be a mess for all vendors and customers in the .NET ecosystem, for JS ecosystem it would be even worse due to a different NPM package update strategies and the number of updated packages. &lt;strong&gt;In other words, the solution should never be worse than the original problem.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id="additional-information" style="color:#505050;font-weight:600;"&gt;See Also&lt;/h2&gt;

&lt;p&gt;Microsoft clarified this general pattern in their blogs and docs, because this version upgrade is needed regularly:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/nugetaudit-2-0-elevating-security-and-trust-in-package-management/#how-to-upgrade-transitive-packages" rel="nofollow"&gt;NuGetAudit 2.0: Elevating Security and Trust in Package Management&lt;/a&gt; (see the &amp;quot;How to upgrade transitive packages&amp;quot; section)&lt;/li&gt;&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management#overriding-package-versions" rel="nofollow"&gt;Overriding Package Versions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also described how to fix this and similar customer issues at &lt;a href="https://community.devexpress.com/blogs/news/archive/2024/07/18/dot-net-nuget-package-audit-and-false-positive-security-warnings.aspx"&gt;.NET — About NuGet Package Audit and &amp;quot;False-Positive&amp;quot; Security Warnings&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Please let me know if you have any DevExpress-related questions or suggestions.&lt;/p&gt;&lt;p&gt;&lt;span&gt;Thanks,&lt;/span&gt;&lt;br&gt;&lt;span&gt;Dennis Garavsky&lt;/span&gt;&lt;br&gt;&lt;span&gt;Principal Product Manager&lt;/span&gt;&lt;br&gt;&lt;a href="mailto:dennis@devexpress.com" title="Email me if you have questions or suggestions"&gt;dennis@devexpress.com&lt;/a&gt;&lt;br&gt;&lt;/p&gt;</description>
      <pubDate>Fri, 24 Apr 2026 09:44:00 Z</pubDate>
      <dc:creator>Dennis Garavsky (DevExpress)</dc:creator>
    </item>
    <item>
      <guid isPermaLink="false">bd716303-653c-428d-8b8a-a7d998cde032:388284</guid>
      <link>https://community.devexpress.com/Blogs/news/archive/2026/04/17/application-security-stronger-hashes-and-safer-passwords.aspx</link>
      <category domain="https://community.devexpress.com/Tags/.NET">.NET</category>
      <category domain="https://community.devexpress.com/Tags/.net+core">.net core</category>
      <category domain="https://community.devexpress.com/Tags/Architecture">Architecture</category>
      <category domain="https://community.devexpress.com/Tags/ASP.NET">ASP.NET</category>
      <category domain="https://community.devexpress.com/Tags/Blazor">Blazor</category>
      <category domain="https://community.devexpress.com/Tags/Dashboard">Dashboard</category>
      <category domain="https://community.devexpress.com/Tags/Data+Access">Data Access</category>
      <category domain="https://community.devexpress.com/Tags/Office+File+API">Office File API</category>
      <category domain="https://community.devexpress.com/Tags/Reporting">Reporting</category>
      <category domain="https://community.devexpress.com/Tags/security">security</category>
      <category domain="https://community.devexpress.com/Tags/WinForms">WinForms</category>
      <category domain="https://community.devexpress.com/Tags/WPF">WPF</category>
      <category domain="https://community.devexpress.com/Tags/XAF">XAF</category>
      <title>Application Security — Stronger Hashes and Safer Passwords</title>
      <description>&lt;p&gt;Every application that stores passwords makes an implicit bet: that the hashing
algorithm it chose will remain strong enough to resist attacks for as long as
those hashes exist. It’s worth revisiting that bet regularly. This post walks
through the reasoning behind some recent changes we’ve made to password hashing
across DevExpress components, and covers broader principles that apply whether
you use our tools or not.&lt;/p&gt;
&lt;h2 id="a-quick-primer-on-password-hashing"&gt;A Quick Primer on Password Hashing&lt;/h2&gt;
&lt;p&gt;A hash function takes an input - say, a password - and produces a fixed-length
string that looks nothing like the original. The critical property is that this
transformation is one-way: given the hash, it should be computationally
impossible to recover the original password.&lt;/p&gt;
&lt;p&gt;Here’s a concise example using the .NET class &lt;code&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rfc2898derivebytes?view=net-10.0" target="_blank"&gt;Rfc2898DeriveBytes&lt;/a&gt;&lt;/code&gt;, which
implements the PBKDF2 algorithm:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp" data-line-numbers="true"&gt;using System.Security.Cryptography;

byte[] salt = RandomNumberGenerator.GetBytes(16);
int iterations = 600_000;

byte[] hash = Rfc2898DeriveBytes.Pbkdf2(
    password: &amp;quot;correct-horse-battery-staple&amp;quot;,
    salt: salt,
    iterations: iterations,
    hashAlgorithm: HashAlgorithmName.SHA512,
    outputLength: 64);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The salt ensures that identical passwords produce different hashes. The
iteration count controls how much computational work is required to produce each
hash, making brute-force attacks proportionally more expensive. And the choice
of hash algorithm matters more than you might think, as I’ll discuss below.&lt;/p&gt;&lt;div class="Note"&gt;&lt;span style="color:#333333;"&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: The low-level code above is intended primarily for demonstration purposes. For production-ready password hashing and storage, you may&amp;nbsp;end up with a more sophisticated implementation based on Rfc2898DeriveBytes and other built-in .NET helpers. For instance, in modern ASP.NET Core&amp;nbsp;applications with Identity (Blazor, Web API, Minimal APIs, ASP.NET Core MVC, Razor Pages, gRPC), you can use&amp;nbsp;&lt;/span&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.passwordhasher-1?view=aspnetcore-10.0" style="color:#337ab7;"&gt;PasswordHasher&amp;lt;TUser&amp;gt;&lt;/a&gt;&amp;nbsp;&lt;span style="color:#333333;"&gt;(Microsoft&amp;#39;s recommendation -&amp;nbsp;&lt;/span&gt;&lt;a href="https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/consumer-apis/password-hashing?view=aspnetcore-10.0" target="_blank"&gt;see below&lt;/a&gt;&lt;span style="color:#333333;"&gt;)&lt;/span&gt;&lt;span style="color:#333333;"&gt;. Similar APIs can be used for other platforms: our XAF framework (for Blazor/WinForms UI and Web API)&amp;nbsp;includes a&amp;nbsp;&lt;/span&gt;&lt;a href="https://docs.devexpress.com/eXpressAppFramework/112649/data-security-and-safety/security-system/authentication/passwords-in-the-security-system#access-passwords-in-code" style="color:#337ab7;"&gt;PasswordCryptographer&lt;/a&gt;&lt;span style="color:#333333;"&gt;&amp;nbsp;helper powered by Rfc2898DeriveBytes&amp;nbsp;with additional configuration options.&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;span style="color:#333333;"&gt;&lt;img src="https://community.devexpress.com/blogs/news/image_3.png" alt=""&gt;&lt;br&gt;&lt;/span&gt;&lt;br&gt;&lt;/p&gt;
&lt;h2 id="document-protection-sha-512-for-office-documents"&gt;Document Protection: SHA-512 for Office Documents&lt;/h2&gt;
&lt;p&gt;If you’ve used document protection in Word-compatible file formats, you know
that it’s an “advisory” protection mechanism. It signals that a document
shouldn’t be edited, but it’s ultimately up to the consuming application to
check and enforce that flag. Document protection is not an encryption mechanism
designed to provide strong security.&lt;/p&gt;
&lt;p&gt;Even so, the protection password hash is stored inside the document. While these
passwords are often shared with collaborators and hopefully aren’t reused for
online banking, there’s still no good reason to make it easy for someone to
brute-force the original password. In v26.1, our
&lt;a href="https://docs.devexpress.com/OfficeFileAPI/DevExpress.XtraRichEdit.API.Native.Document.Protect.overloads" rel="nofollow noreferrer" target="_blank"&gt;&lt;code&gt;Document.Protect&lt;/code&gt;&lt;/a&gt;
method&amp;nbsp;uses the strongest hash function supported by the Office format, as
&lt;a href="https://learn.microsoft.com/en-us/openspecs/office_standards/ms-oe376/fb220a2f-88d4-488c-a9b7-e094756b6699" rel="nofollow noreferrer" target="_blank"&gt;documented by
Microsoft&lt;/a&gt;. You
can find the &lt;a href="https://supportcenter.devexpress.com/ticket/details/t1322324/document-protection-password-protected-documents-now-use-sha-512" rel="nofollow noreferrer" target="_blank"&gt;full details in our breaking change notice&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;See Also:&amp;nbsp;&lt;/strong&gt;&lt;a href="https://community.devexpress.com/Blogs/news/archive/2026/05/29/application-security-documents-are-untrusted-input.aspx"&gt;Application Security — Documents Are Untrusted Input&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="digital-signatures-ocspclient-defaults-to-sha-512"&gt;Digital Signatures: OcspClient Defaults to SHA-512&lt;/h2&gt;
&lt;p&gt;Password hashes aren’t the only place where hash strength matters. Digital
signatures rely on hash functions too, and a weak hash can undermine the
integrity guarantees that a signature is supposed to provide. With v26.1, the
&lt;code&gt;OcspClient&lt;/code&gt; class used for OCSP (Online Certificate Status Protocol) responses
in our digital signature workflow &lt;a href="https://supportcenter.devexpress.com/ticket/details/t1322321/digital-signatures-ocspclient-now-uses-sha-512-by-default" rel="nofollow noreferrer" target="_blank"&gt;now uses SHA-512 by
default&lt;/a&gt;. This
is a straightforward upgrade that brings the default in line with current best
practices.&lt;/p&gt;
&lt;h2 id="xaf-security-system-sha-512-with-600000-iterations"&gt;XAF Security System: SHA-512 with 600000 Iterations&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://docs.devexpress.com/eXpressAppFramework/113366/data-security-and-safety/security-system" target="_blank"&gt;XAF’s built-in Security System&lt;/a&gt; handles full user account management, including
password storage. This is the scenario where hashing strength matters most,
since these are real user passwords protecting real application access.&lt;/p&gt;
&lt;p&gt;With v26.1, we’re configuring the default hash mechanism to use SHA-512 with
600000 iterations of PBKDF2. This is a significant step up from previous
defaults. Because this change affects how stored passwords are verified, it can be considered a&amp;nbsp;&lt;a href="https://supportcenter.devexpress.com/ticket/details/t1325657/xaf-security-a-stronger-password-hashing-algorithm-has-been-configured" rel="nofollow noreferrer" target="_blank"&gt;breaking change (full documentation and migration guidance is
available
here&lt;/a&gt;). We’ll
provide detailed steps to help you update your application and migrate existing
password hashes to the new configuration.&lt;/p&gt;
&lt;h2 id="why-these-specific-choices"&gt;Why These Specific Choices?&lt;/h2&gt;
&lt;p&gt;You might wonder: why SHA-512? Why 600000 iterations? Why not something else entirely?&lt;/p&gt;
&lt;p&gt;The short answer is that we’re following the &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html" rel="nofollow noreferrer" target="_blank"&gt;OWASP Password Storage Cheat
Sheet&lt;/a&gt;,
specifically its guidance on PBKDF2 for environments that require FIPS-140
compliance. OWASP is widely regarded as the authoritative source for application
security best practices, and their recommendations are well-researched,
regularly updated, and practical.&lt;/p&gt;
&lt;p&gt;If you handle passwords in your own applications - whether for storage,
verification, or any other processing - reading the OWASP guidance in detail is
highly recommended. It’s clearly written and covers important related concepts like
the salts mentioned above (random values mixed into each hash to prevent precomputed attacks)
and peppers (application-level secrets added as an extra layer of defense).&lt;/p&gt;
&lt;p&gt;That said, there are two important points worth expanding on in the context of
the choices we made.&lt;/p&gt;&lt;div class="Note"&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: As of this writing, SHA-256 remains a fully valid, supported, and widely recommended choice (including the current OWASP and NIST guidance). Despite a larger output size, SHA-512 can be as fast as SHA-256 on modern 64-bit hardware. In practice, the overall security is driven by many more factors (like iteration count, rate limiting, and algorithm design, etc.) than the output length of a specific SHA-XXX algorithm.&lt;br&gt;&lt;/div&gt;
&lt;h2 id="point-1-iteration-count-is-a-trade-off-and-rate-limiting-is-non-negotiable"&gt;Point 1: Iteration Count Is a Trade-Off, and Rate Limiting Is Non-Negotiable&lt;/h2&gt;
&lt;p&gt;The OWASP guidance for PBKDF2 with SHA-512 suggests an iteration count that is
actually somewhat lower than the 600000 we adopted for XAF. That’s because
iteration count is a trade-off between security and performance: more iterations
mean more work for an attacker, but also more work for your server on every
legitimate login.&lt;/p&gt;
&lt;p&gt;To make an informed choice, think about where and when your application computes
password hashes. How frequently does it happen? What does the load look like
during peak usage? Measure how long a single hash computation takes on your
hardware. These data points, combined with the OWASP guidance, will help you
find the right balance for your specific situation.&lt;/p&gt;
&lt;p&gt;This line of thinking leads to a critical complementary measure: rate
limiting. No matter how strong your hash function is, if an attacker can make
unlimited login attempts, they have unlimited opportunities to guess
passwords. Rate limiting caps the number of attempts in a given time window,
making brute-force attacks impractical even against weaker hashes.&lt;/p&gt;
&lt;p&gt;You want this at two levels. At the application level, lock out individual
accounts after repeated failures. ASP.NET Core Identity supports this through
the
&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.lockoutoptions.maxfailedaccessattempts" rel="nofollow noreferrer" target="_blank"&gt;&lt;code&gt;LockoutOptions.MaxFailedAccessAttempts&lt;/code&gt;&lt;/a&gt;
property in the &lt;code&gt;IdentityOptions.Lockout&lt;/code&gt; configuration, and the XAF Security
System offers equivalent functionality with the
&lt;a href="https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.Security.ISecurityUserLockout" rel="nofollow noreferrer" target="_blank"&gt;&lt;code&gt;ISecurityUserLockout&lt;/code&gt;&lt;/a&gt;
interface. At the edge, protect your infrastructure from being overwhelmed, by
using a WAF (Web Application Firewall), Cloudflare, or a reverse proxy like
Nginx or Caddy with built-in rate limiting. Use both techniques: account lockout
and infrastructure protection solve different problems.&lt;/p&gt;
&lt;h2 id="point-2-pbkdf2-vs-memory-hard-algorithms---the-state-of-the-art"&gt;Point 2: PBKDF2 vs. Memory-Hard Algorithms - the State of the Art&lt;/h2&gt;
&lt;p&gt;If you read the OWASP cheat sheet closely, you’ll notice that PBKDF2 is
positioned as the last choice in their ranked list of recommended
algorithms. OWASP explicitly notes that PBKDF2 is the best option only when
FIPS-140 compliance is required.&lt;/p&gt;
&lt;p&gt;The reason is architectural. PBKDF2 is a CPU-bound algorithm, its security
relies on requiring many sequential computations. The problem is that modern
GPUs and purpose-built ASIC chips can perform these computations orders of magnitude
faster than general-purpose CPUs. An attacker with access to specialized
hardware can brute-force PBKDF2 hashes far more efficiently than a defender’s
server can compute them. Some hardware of this nature can be rented conveniently
in the cloud, making it accessible to a wide range of attackers.&lt;/p&gt;
&lt;p&gt;OWASP’s preferred alternatives are memory-hard algorithms like Argon2id and
scrypt. These algorithms are designed to require large amounts of memory during
computation, which makes them resistant to GPU and ASIC attacks. Specialized
hardware is fast at computation but has limited memory bandwidth, which levels
the playing field.&lt;/p&gt;
&lt;p&gt;However, memory-hard algorithms come with trade-offs of their own. Consider the
OWASP-recommended minimum for Argon2id: 19 MiB of memory and 2 iterations per
hash computation. If you need to support just 100 concurrent login attempts,
that’s already 1.9 GiB of memory dedicated solely to password hashing. The
calculation for your maximum concurrent user count becomes a fundamentally
different exercise than with CPU-bound algorithms.&lt;/p&gt;
&lt;p&gt;There’s also a practical consideration in the .NET ecosystem: Argon2id and
scrypt are not natively supported by the .NET runtime. Using them requires
third-party libraries, which introduces dependencies on external maintainers for
security-critical code. Many developers and organizations reasonably conclude
that a well-configured, natively supported algorithm - PBKDF2 with SHA-512 and a
high iteration count - is preferable to taking on that dependency risk. This is
the reasoning behind our choice for DevExpress products.&lt;/p&gt;
&lt;h2 id="the-bottom-line"&gt;The Bottom Line&lt;/h2&gt;
&lt;p&gt;Password hashing is one of those areas where “good enough” has a shelf
life. Algorithms that were considered strong a few years ago may no longer
provide adequate protection against modern hardware. The updates we’re shipping
in v26.1 reflect current best practices, and we encourage you to review your own
applications with the same critical eye, if you handle passwords in any capacity.&lt;/p&gt;

&lt;h2&gt;Your Feedback Matters!&lt;/h2&gt;
&lt;div data-survey-id="b31c0c9e-b420-4b2b-9501-2a16d14dd7af" data-survey-auth-required="false"&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 17 Apr 2026 11:00:00 Z</pubDate>
      <dc:creator>Oliver Sturm (DevExpress)</dc:creator>
    </item>
    <item>
      <guid isPermaLink="false">bd716303-653c-428d-8b8a-a7d998cde032:388282</guid>
      <link>https://community.devexpress.com/Blogs/news/archive/2026/04/02/application-security-why-you-cant-protect-your-connection-string.aspx</link>
      <category domain="https://community.devexpress.com/Tags/.NET">.NET</category>
      <category domain="https://community.devexpress.com/Tags/.net+core">.net core</category>
      <category domain="https://community.devexpress.com/Tags/Architecture">Architecture</category>
      <category domain="https://community.devexpress.com/Tags/Backend">Backend</category>
      <category domain="https://community.devexpress.com/Tags/Data+Access">Data Access</category>
      <category domain="https://community.devexpress.com/Tags/database">database</category>
      <category domain="https://community.devexpress.com/Tags/Desktop">Desktop</category>
      <category domain="https://community.devexpress.com/Tags/Frontend">Frontend</category>
      <category domain="https://community.devexpress.com/Tags/Middle+Tier">Middle Tier</category>
      <category domain="https://community.devexpress.com/Tags/ORM">ORM</category>
      <category domain="https://community.devexpress.com/Tags/RDBMS">RDBMS</category>
      <category domain="https://community.devexpress.com/Tags/REST">REST</category>
      <category domain="https://community.devexpress.com/Tags/security">security</category>
      <category domain="https://community.devexpress.com/Tags/webapi">webapi</category>
      <category domain="https://community.devexpress.com/Tags/windows">windows</category>
      <category domain="https://community.devexpress.com/Tags/WinForms">WinForms</category>
      <category domain="https://community.devexpress.com/Tags/WPF">WPF</category>
      <title>Application Security — Why One Does Not Simply Protect a Data Store Connection String and Other Login Credentials?</title>
      <description>&lt;p&gt;A developer asks: “How do I protect my connection string in a desktop
application?”&lt;/p&gt;
&lt;p&gt;This is one of the most common security questions in .NET development, and it
sounds like it should have a straightforward answer. But there is a fundamental
problem we need to analyze.&lt;/p&gt;
&lt;p&gt;When an application connects to a service, SQL Server, a REST API, any service
at all, it needs credentials. That’s unavoidable.&lt;/p&gt;
&lt;p&gt;Sometimes those are long-lived “root” credentials: usernames and passwords, API
keys, client secrets. Sometimes they’re derived tokens with limited scope and
lifetime. Sometimes they come from the environment, like Windows
Authentication. The exact form doesn’t matter.&lt;/p&gt;
&lt;p&gt;What matters is this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;At the moment your application uses those credentials, it has everything it
needs to act on them.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And that leads directly to a part which is easily underestimated.&lt;/p&gt;
&lt;h2 id="the-reality-of-using-credentials"&gt;The reality of using credentials&lt;/h2&gt;
&lt;p&gt;If your application can use credentials, then anything that can control your
application can use them too.&lt;/p&gt;
&lt;p&gt;On a typical desktop system, the user fully controls the machine. That means
they can inspect memory, attach a debugger, intercept calls, or simply drive the
application in ways you didn’t intend.&lt;/p&gt;
&lt;p&gt;To illustrate: a connection string used by an application through Entity
Framework or ADO.NET can typically be found in plain text in a process memory
dump, using standard tools like WinDbg or dotnet-dump. No reverse engineering
required.&lt;/p&gt;
&lt;p&gt;Managed enterprise environments can raise the cost of such attacks
significantly, through tools like AppLocker, WDAC, or restricted user
accounts. But the fundamental dynamic does not change: the complexity of
exploitation increases, while the possibility remains. This applies to WPF or
Windows Forms applications, other types of native applications, and also to
server applications like those served by a web server.&lt;/p&gt;
&lt;p&gt;If your application uses a secret to access a remote resource, you can try to
hide the secret. You can encrypt it at rest. You can obfuscate it.&lt;/p&gt;
&lt;p&gt;But none of that changes the core fact: &lt;strong&gt;the application itself is already
authenticated, at the point where it works with the remote resource&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;An attacker doesn’t need to extract the password if they can just make your
application run the query, call the API, or perform the operation on their
behalf.&lt;/p&gt;
&lt;p&gt;This is a key point that many discussions miss. The problem is not just that
secrets can be stolen. It’s that the application already embodies the permission
those secrets grant.&lt;/p&gt;
&lt;h2 id="so-can-we-protect-connection-strings"&gt;So can we protect connection strings?&lt;/h2&gt;
&lt;p&gt;Not in the way people often expect. If someone can run code on the same machine,
under the same user account as your application, they can make your application
do anything it is allowed to do. That’s not a framework limitation or a missing
feature. It’s simply how software works.&lt;/p&gt;
&lt;p&gt;Microsoft’s own guidance reflects this reality indirectly. For example, Entity
Framework explicitly recommends &lt;strong&gt;not&lt;/strong&gt; relying on storing connection strings
with sensitive information directly in application configuration, and instead
using more secure patterns where possible (see: &lt;a href="https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/ef/security-considerations#secure-the-connection-string" rel="nofollow noreferrer" target="_blank"&gt;Entity Framework Core
connection string
guidance&lt;/a&gt;). Guidelines
for ASP.NET Core go in the same direction, &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-10.0#security-and-user-secrets" rel="nofollow noreferrer" target="_blank"&gt;you can read them
here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For development, Microsoft recommends the use of &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-10.0" rel="nofollow noreferrer" target="_blank"&gt;the Secret Manager
tool&lt;/a&gt;. Note
that it is meant to be used for development purposes only! Local storage
mechanisms are for convenience and isolation - not for real security
boundaries. The fundamental issue isn’t changed by the use of these tools:
locally stored secrets are not safe from the user of the machine.&lt;/p&gt;
&lt;p&gt;The .NET platform itself does not provide a single, clear, production-ready
solution for secure storage on client machines. Its built-in configuration
system can read values from many sources, but it does not make those sources
secure.&lt;/p&gt;
&lt;p&gt;In Microsoft’s more current guidance, the picture does not fundamentally
change. For example, documentation for
&lt;a href="https://learn.microsoft.com/en-us/entra/msal/dotnet/how-to/token-cache-serialization?tabs=desktop" rel="nofollow noreferrer" target="_blank"&gt;MSAL.NET&lt;/a&gt;,
specifically for desktop apps, recommends persisting token caches locally and,
on Windows, protecting them using DPAPI or similar mechanisms. In other words,
the responsibility for secure storage remains with the application and the
underlying operating system rather than the .NET framework itself.&lt;/p&gt;
&lt;p&gt;Integrating facilities such as DPAPI or the Windows Credential Manager with
application configuration often requires additional code or libraries, as there
is no standard built-in bridge between secure OS storage and the .NET
configuration system. The documentation for MSAL.NET, linked just above,
includes mention of the &lt;code&gt;Microsoft.Identity.Client.Extensions.Msal&lt;/code&gt; NuGet
package, which has persistence support for token caches. The best recommendation
for general purpose secret persistence however is &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.protecteddata?view=windowsdesktop-10.0" rel="nofollow noreferrer" target="_blank"&gt;the ProtectedData
class&lt;/a&gt;. There
are third party NuGet packages in this space as well, but trustworthiness is a
concern for such an important feature.&lt;/p&gt;
&lt;h2 id="what-actually-helps"&gt;What actually helps&lt;/h2&gt;
&lt;p&gt;Once you accept that secrets inside a client application cannot be fully
protected, the question changes. It’s no longer &lt;em&gt;how do I hide this credential?&lt;/em&gt;
but &lt;em&gt;how do I limit the damage when it’s used by the wrong person?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There are two strategies, and they work best together.&lt;/p&gt;
&lt;h3 id="make-credentials-less-worth-stealing"&gt;Make credentials less worth stealing&lt;/h3&gt;
&lt;p&gt;If a credential is compromised, how much damage can it do? The answer should be:
as little as possible.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Restrict permissions to the minimum required&lt;/li&gt;
&lt;li&gt;Scope credentials to specific operations&lt;/li&gt;
&lt;li&gt;Prefer short-lived tokens over long-lived root secrets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is where modern identity systems earn their keep, whether
cloud-based or self-hosted. OpenID Connect providers, managed identities, token
services, they don’t hide secrets better. They issue weaker, narrower ones, secrets of
much lower value to a potential hacker.&lt;/p&gt;
&lt;h3 id="reduce-the-blast-radius"&gt;Reduce the blast radius&lt;/h3&gt;
&lt;p&gt;If a credential or an application is compromised, how far can the damage spread?
There are two ways to constrain it: change the architecture, or change the
environment.&lt;/p&gt;
&lt;p&gt;Changing the architecture is the most powerful option: instead of giving a
client direct access to a database, you introduce a service layer. The client
talks to an API, the API talks to the database.&lt;/p&gt;
&lt;p&gt;Now the high-value credentials live in a controlled environment: on a server you
manage, not on every user’s machine. The API of that server, the services it
publishes, define what is possible. A connection string allows arbitrary SQL. An
API should not.&lt;/p&gt;
&lt;p&gt;A service layer also solves another problem: it decouples client authentication
from backend authentication. If your database or backend service only supports
long-lived credentials, the API can still offer token-based, short-lived access
to clients. The powerful credential stays on the server, the client never sees
it.&lt;/p&gt;
&lt;p&gt;The narrower and more specific your API is, the less damage can be done. Of
course the client will still need credentials to access the API, but with a
careful structure potential damage is very limited even if a client is fully
compromised.&lt;/p&gt;
&lt;p&gt;This idea can also be extended to the client environment itself. In managed
Windows environments, administrators can reduce the blast radius further by
restricting what users are allowed to do on the machine: limiting which
applications can be executed (e.g. via AppLocker or Windows Defender Application
Control), enforcing restricted user accounts, or even locking systems into
kiosk-style operation. These measures do not eliminate the underlying issue, but
they can make it significantly harder to exploit in practice by removing the
ability to run arbitrary code alongside the application.&lt;/p&gt;
&lt;p&gt;A service layer also opens up an entire category of server-side protections that
are simply impossible to enforce on a client machine: rate limiting, anomaly
detection, device or IP binding, audit logging. These don’t prevent credential
misuse on their own, but they make abuse observable and containable - and they
only become options once privileged access has moved off the client.&lt;/p&gt;
&lt;h2 id="the-path-most-people-take"&gt;The path most people take&lt;/h2&gt;
&lt;p&gt;In practice, developers rarely jump straight to architectural changes. They tend
to go through a series of steps.&lt;/p&gt;
&lt;p&gt;First, they look for ways to avoid handling credentials at all, using Windows
Authentication or similar mechanisms. If that works, it’s ideal.&lt;/p&gt;
&lt;p&gt;If this is not an option, the second-best approach is to avoid embedding
powerful credentials directly, introducing identity providers or token-based
access instead.&lt;/p&gt;
&lt;p&gt;As long as any credentials need to be stored on the client machine, secure
storage becomes a concern - options have been discussed above.&lt;/p&gt;
&lt;p&gt;At this point, many developers feel they’ve “secured” their application. But if
you follow the logic from earlier, you arrive at an uncomfortable conclusion:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;None of these steps prevent a determined attacker with control over the
machine from using the application’s access.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And that’s where the final step becomes unavoidable.&lt;/p&gt;
&lt;h2 id="when-architecture-is-the-only-real-fix"&gt;When architecture is the only real fix&lt;/h2&gt;
&lt;p&gt;If the risk still matters - and in many systems it does! - the only meaningful
improvement comes from changing the shape of the system.&lt;/p&gt;
&lt;p&gt;Move privileged access away from the client. Introduce services. Narrow what
those services do.&lt;/p&gt;
&lt;p&gt;This doesn’t make your system invulnerable. But it changes the game from &lt;em&gt;anyone
with access can do anything&lt;/em&gt; to &lt;em&gt;even with access, only specific actions are
possible&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;That’s a huge difference.&lt;/p&gt;
&lt;p&gt;I strongly recommend reading our &lt;a href="https://community.devexpress.com/Tags/rbac" target="_blank"&gt;related blog series&lt;/a&gt;&amp;nbsp;(starting with &lt;a href="https://community.devexpress.com/blogs/news/archive/2024/02/09/modern-desktop-apps-and-their-complex-architectures.aspx" target="_blank" rel="nofollow noreferrer"&gt;Modern Desktop Apps And Their Complex Architectures&lt;/a&gt;) and&amp;nbsp;documentation pages about the &lt;a href="https://docs.devexpress.com/eXpressAppFramework/403394/backend-web-api-service" rel="nofollow noreferrer" target="_blank"&gt;Backend Web API Service&lt;/a&gt;, &lt;a href="https://docs.devexpress.com/WindowsForms/405145/data-access-security" rel="nofollow noreferrer" target="_blank"&gt;Data Access
Security&lt;/a&gt;,
and &lt;a href="https://docs.devexpress.com/eXpressAppFramework/404691/security-considerations/general-security-considerations#security-tiers" rel="nofollow noreferrer" target="_blank"&gt;XAF Security
Tiers&lt;/a&gt;. They go into more detail about how to design systems with these principles in
mind. Of course this approach is complex and specific to your application, its
architecture and requirements. Please don’t hesitate to reach out if we can
help!&lt;/p&gt;
&lt;h2 id="a-common-misconception-securestring"&gt;A common misconception: .NET &amp;quot;Secure&amp;quot; String&lt;/h2&gt;
&lt;p&gt;This comes up often enough to be worth addressing directly, in a few words.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.security.securestring" target="_blank"&gt;SecureString&lt;/a&gt; was designed to minimize the time secrets exist in memory in
plain text. In theory, that sounds helpful.&lt;/p&gt;
&lt;p&gt;In practice, especially in the managed .NET environment, it does little to solve
the problem. There are two reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Most APIs which connect you to services require “normal” strings, so the
secure in-memory representation &lt;code&gt;SecureString&lt;/code&gt; offers needs to be converted
into .NET strings. These conversions leave data in managed memory, just as if
you’d stored it there all along.&lt;/li&gt;
&lt;li&gt;Even if this could be prevented, the application still performs authenticated
operations. This leaves it open to control by a local user just like before.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So while it may reduce exposure in very narrow scenarios, it does nothing to
address the fundamental issue: the application already has the capability to
act. Finally, it&amp;#39;s difficult to ignore the&amp;nbsp;official Microsoft recommendations (&lt;a href="https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md" target="_blank"&gt;one&lt;/a&gt;,&amp;nbsp;&lt;a href="https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-security-securestring" target="_blank"&gt;two&lt;/a&gt;, &lt;a href="https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-security-securestring#how-secure-is-securestring" target="_blank"&gt;three&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;&lt;img src="https://community.devexpress.com/blogs/news/image_2.png" alt=""&gt;&lt;/p&gt;&lt;h2&gt;Your Feedback Matters!&lt;/h2&gt;
&lt;div data-survey-id="b31c0c9e-b420-4b2b-9501-2a16d14dd7af" data-survey-auth-required="false"&gt;&lt;/div&gt;</description>
      <pubDate>Thu, 02 Apr 2026 11:00:00 Z</pubDate>
      <dc:creator>Oliver Sturm (DevExpress)</dc:creator>
    </item>
    <item>
      <guid isPermaLink="false">bd716303-653c-428d-8b8a-a7d998cde032:388283</guid>
      <link>https://community.devexpress.com/Blogs/news/archive/2026/04/01/microsoft-multilingual-app-toolkit-mat-has-been-deprecated-what-s-next-for-devexpress-powered-app-localization.aspx</link>
      <category domain="https://community.devexpress.com/Tags/.NET">.NET</category>
      <category domain="https://community.devexpress.com/Tags/.net+core">.net core</category>
      <category domain="https://community.devexpress.com/Tags/ASP.NET">ASP.NET</category>
      <category domain="https://community.devexpress.com/Tags/Blazor">Blazor</category>
      <category domain="https://community.devexpress.com/Tags/charting">charting</category>
      <category domain="https://community.devexpress.com/Tags/Dashboard">Dashboard</category>
      <category domain="https://community.devexpress.com/Tags/DevExtreme">DevExtreme</category>
      <category domain="https://community.devexpress.com/Tags/Featured">Featured</category>
      <category domain="https://community.devexpress.com/Tags/feedback">feedback</category>
      <category domain="https://community.devexpress.com/Tags/future">future</category>
      <category domain="https://community.devexpress.com/Tags/globalization">globalization</category>
      <category domain="https://community.devexpress.com/Tags/JS">JS</category>
      <category domain="https://community.devexpress.com/Tags/localization">localization</category>
      <category domain="https://community.devexpress.com/Tags/office">office</category>
      <category domain="https://community.devexpress.com/Tags/Reporting">Reporting</category>
      <category domain="https://community.devexpress.com/Tags/Roadmap">Roadmap</category>
      <category domain="https://community.devexpress.com/Tags/Survey">Survey</category>
      <category domain="https://community.devexpress.com/Tags/usability">usability</category>
      <category domain="https://community.devexpress.com/Tags/ux">ux</category>
      <category domain="https://community.devexpress.com/Tags/VCL">VCL</category>
      <category domain="https://community.devexpress.com/Tags/WinForms">WinForms</category>
      <category domain="https://community.devexpress.com/Tags/WPF">WPF</category>
      <category domain="https://community.devexpress.com/Tags/XAF">XAF</category>
      <title>Microsoft Multilingual App Toolkit (MAT) Has Been Deprecated: What’s Next for DevExpress-Powered App Localization?</title>
      <description>&lt;p&gt;&lt;span style="color:#000000;"&gt;As you probably know,&amp;nbsp;Microsoft Multilingual App Toolkit (MAT)&amp;nbsp;support ended&amp;nbsp;on October 15, 2025. Since MAT&amp;nbsp;is no longer supported, this post documents&amp;nbsp;localization-related alternatives available to the Microsoft developer community.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;h2 style="color:#242424;"&gt;&lt;span&gt;What MAT Deprecation Means in Practice&lt;/span&gt;&lt;/h2&gt;&lt;ul style="color:#242424;"&gt;&lt;li&gt;No future compatibility guarantees with new tooling or runtimes.&lt;/li&gt;&lt;li&gt;Localization assets are not lost&amp;nbsp;— MAT uses standard XLIFF / RESX formats,&amp;nbsp;so translations remain reusable.&lt;/li&gt;&lt;li&gt;Microsoft recommends moving to alternative localization tools.&lt;/li&gt;&lt;/ul&gt;&lt;h2 style="color:#242424;"&gt;&lt;span&gt;What to Look for in a MAT Alternative&lt;/span&gt;&lt;br&gt;&lt;/h2&gt;&lt;p style="color:#242424;"&gt;&lt;span&gt;Key requirements for .NET apps:&lt;/span&gt;&lt;/p&gt;&lt;ul style="color:#242424;"&gt;&lt;li&gt;Centralized localization string management&lt;/li&gt;&lt;li&gt;Validation and consistency checks&lt;/li&gt;&lt;li&gt;Reuse of translations across versions&lt;/li&gt;&lt;li&gt;Support for RESX/XLIFF-based workflows&lt;/li&gt;&lt;/ul&gt;&lt;h2 style="color:#242424;"&gt;&lt;span&gt;New DevExpress Localization Tool at a Glance&lt;/span&gt;&lt;br&gt;&lt;/h2&gt;&lt;p style="color:#242424;"&gt;&lt;span&gt;All the aforementioned localization requirements are supported in the new &lt;a href="https://docs.devexpress.com/GeneralInformation/405620/localization/localization-tool" target="_blank" style="background-color:#ffff99;"&gt;DevExpress Localization Tool&lt;/a&gt; (available as Community Technology Preview or CTP&amp;nbsp;in v25.2): &lt;span style="background-color:#ffff99;"&gt;&lt;a href="https://github.com/DevExpress/Localization" target="_blank"&gt;Downloads&lt;/a&gt; | &lt;a href="https://docs.devexpress.com/GeneralInformation/404608/localization/localization-tool" target="_blank"&gt;Get Started&lt;/a&gt;&lt;/span&gt;.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style="color:#242424;"&gt;&lt;span style="color:#404040;"&gt;This new tool introduces enhanced collaboration capabilities, easier resource navigation/management, AI-powered translation services, support for multiple DevExpress products/platforms, and much more.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Key features include:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Simpler localization string management&lt;/strong&gt;&lt;br&gt;Use advanced data shaping capabilities available in our Data Grid control to locate resources, filter or group data, and more.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Enhanced translation consistency and coverage&lt;/strong&gt;&lt;br&gt;Locate duplicate strings, find inconsistent translations using a built-in localization validator, review context information, and run batch operations.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Multiple export types&lt;/strong&gt;&lt;br&gt;You can export translations as satellite assemblies, NuGet packages, a single merged RESX file for multiple products (replaces hundreds of assemblies), or JSON files for JS/TS-based products.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New collaboration capabilities&lt;/strong&gt;&lt;br&gt;You can now use change tracking, reviews, import/export capabilities, and built-in backups. All DevExpress product localization resources are available on GitHub. You can either use our Windows-based tool, modify your translations directly in RESX/XML, or build your own tool.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Support for multiple products/platforms&lt;/strong&gt;&lt;br&gt;The current version already supports numerous DevExpress UI libraries (WinForms, WPF, Blazor, ASP.NET Core, Reports, Dashboard, XAF). We plan to add support for .NET MAUI, DevExtreme, and VCL UI Controls in future release cycles.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;AI-powered resource translation&lt;/strong&gt;&lt;br&gt;Integrate your favorite AI service into our new Localization client.&lt;/li&gt;&lt;/ul&gt;&lt;p style="color:#242424;"&gt;&lt;span&gt;&lt;img src="https://www.devexpress.com/subscriptions/i/25.2/25-2-localization-tool@2x.png" alt=""&gt;&lt;br&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="color:#242424;"&gt;&lt;span&gt;&lt;strong&gt;My favorite feature&lt;/strong&gt;&lt;span&gt;: a way to export all your multi-product translations to a &lt;a href="https://docs.devexpress.com/GeneralInformation/405620/localization/localization-tool#export-to-mergedsingle-resx" target="_blank" style="background-color:#ffff99;"&gt;single or merged RESX file&lt;/a&gt;. This is a huge time-saver or much simpler alternative to dozens of NuGet packages or satellite resources/assemblies (this&amp;nbsp;standard .NET approach is still supported). A single RESX file under your control means fewer dependencies in projects: no accidentally forgotten references and no heavy maintenance later when you add a new component to the project.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="color:#242424;"&gt;&lt;span&gt;&lt;img src="https://community.devexpress.com/blogs/news/single_localization_resource.png" alt="" style="width:1514px;height:896px;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="color:#242424;"&gt;&lt;span&gt;&lt;span&gt;The fact that the&amp;nbsp;source translations&amp;nbsp;reside&amp;nbsp;on GitHub and the internal translation database (RESX/XML)&amp;nbsp;is accessible for custom tools (yes, our customers did that too)&amp;nbsp;or AI-based translations are&amp;nbsp;nice additions as well. I also think that our powerful WinForms Data Grid speaks for itself.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="color:#242424;"&gt;&lt;span&gt;&lt;img src="https://community.devexpress.com/blogs/news/machine_readable_sources_collage.png" alt="" style="width:2146px;height:1089px;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;h2 style="color:#242424;"&gt;&lt;span&gt;Future Plans&lt;/span&gt;&lt;/h2&gt;&lt;p style="color:#242424;"&gt;&lt;span&gt;Long-term goal: one unified localization platform (even for VCL and JS) instead of multiple overlapping tools.&amp;nbsp;&lt;/span&gt;In 2026, we will improve ease of use/usability as follows:&lt;/p&gt;&lt;ul style="color:#242424;"&gt;&lt;li&gt;Automatic localization resource downloads vs manual copy/paste from GitHub;&lt;/li&gt;&lt;li&gt;Automatic product selection for localization (based on application DLL)&lt;/li&gt;&lt;li&gt;Better integration with DevExtreme JS / TS (&lt;a href="https://docs.devexpress.com/AspNetCore/400577/devextreme-based-controls/concepts/localization" target="_blank"&gt;Intl and custom dictionaries&lt;/a&gt;), XAF (&lt;a href="https://docs.devexpress.com/eXpressAppFramework/113297/localization/localization-tool" target="_blank"&gt;XAFML files&lt;/a&gt;), VCL (&lt;a href="https://docs.devexpress.com/VCL/154039/ExpressCrossPlatformLibrary/how-to/localize-an-application" target="_blank"&gt;INI files&lt;/a&gt;).​&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;span style="color:#000000;"&gt;Ultimately, the new&amp;nbsp;&lt;a href="https://docs.devexpress.com/GeneralInformation/405620/localization/localization-tool" target="_blank"&gt;DevExpress Localization Tool&lt;/a&gt;&amp;nbsp;offers a modern path forward for DevExpress-powered apps. Older DevExpress localization utilities are now in maintenance mode (see also&amp;nbsp;&lt;a href="https://docs.devexpress.com/GeneralInformation/404608/localization/localization#tools" target="_blank" style="background-color:#ffff99;"&gt;this comparison&lt;/a&gt;). For example, we will continue to maintain the&amp;nbsp;&lt;a href="https://localization.devexpress.com/" target="_blank"&gt;localization.devexpress.com&lt;/a&gt;&amp;nbsp;service as we have no alternatives for older DevExpress product versions, but this service will only receive&amp;nbsp;bug fixes. While you can use&amp;nbsp;the service for new DevExpress versions, we recommend that you give the new tool a&amp;nbsp;try for translation-related tasks (on Windows at least).&lt;/span&gt;&lt;/p&gt;&lt;h2&gt;Your Feedback Matters!&lt;/h2&gt;
&lt;div data-survey-id="16f43533-a02a-43b0-9a22-bbab1c5aa730" data-survey-auth-required="false"&gt;&lt;/div&gt;
&lt;p&gt;&lt;span&gt;Thanks,&lt;/span&gt;&lt;br&gt;&lt;span&gt;Dennis Garavsky&lt;/span&gt;&lt;br&gt;&lt;span&gt;Principal Product Manager&lt;/span&gt;&lt;br&gt;&lt;a href="mailto:dennis@devexpress.com" title="Email me if you have questions or suggestions"&gt;dennis@devexpress.com&lt;/a&gt;&lt;br&gt;&lt;/p&gt;</description>
      <pubDate>Wed, 01 Apr 2026 05:15:00 Z</pubDate>
      <dc:creator>Dennis Garavsky (DevExpress)</dc:creator>
    </item>
    <item>
      <guid isPermaLink="false">bd716303-653c-428d-8b8a-a7d998cde032:388263</guid>
      <link>https://community.devexpress.com/Blogs/news/archive/2025/10/16/transform-your-development-experience-with-the-devexpress-mcp-server.aspx</link>
      <category domain="https://community.devexpress.com/Tags/ai">ai</category>
      <category domain="https://community.devexpress.com/Tags/AI-Assistant">AI-Assistant</category>
      <category domain="https://community.devexpress.com/Tags/Cursor">Cursor</category>
      <category domain="https://community.devexpress.com/Tags/Documentation">Documentation</category>
      <category domain="https://community.devexpress.com/Tags/Featured">Featured</category>
      <category domain="https://community.devexpress.com/Tags/GitHub+Copilot">GitHub Copilot</category>
      <category domain="https://community.devexpress.com/Tags/JetBrains+Rider">JetBrains Rider</category>
      <category domain="https://community.devexpress.com/Tags/MCP">MCP</category>
      <category domain="https://community.devexpress.com/Tags/News">News</category>
      <category domain="https://community.devexpress.com/Tags/Visual+Studio">Visual Studio</category>
      <category domain="https://community.devexpress.com/Tags/VSCode">VSCode</category>
      <title>Transform Your Development Experience with the DevExpress Documentation MCP Server</title>
      <description>&lt;p&gt;The Model Context Protocol (MCP) transforms the way AI assistants interact with external tools and data sources. Developed by Anthropic, MCP is an open standard that allows developers to establish secure, two-way connections between databases, APIs, and AI-powered tools. Instead of building a separate custom integration each time an AI application needs to connect to a data source or API, MCP offers a single, standardized interface. This means each AI app and each external resource only need to connect once, and from there, everything can work together seamlessly.&lt;/p&gt;

&lt;p&gt;To meet growing demand for AI-assisted coding, we’ve configured an MCP server that connects GitHub Copilot and other MCP-compatible AI tools directly to our comprehensive documentation database. We continuously update this database&amp;nbsp;as we enhance existing DevExpress documentation content and publish new help topics. You&amp;#39;ll always have relevant, contextual, and up-to-date guidance for DevExpress components without leaving your IDE. With access to over &lt;strong&gt;300,000 help topics&lt;/strong&gt;, our server makes it easy to find the information you need using natural language queries.&lt;/p&gt;&lt;img src="https://community.devexpress.com/blogs/winforms/20251008-Win-Roadmap-252/dx-mcp-docs-assistant.png" alt="DevExpress MCP Server" style="width:1560px;height:632px;"&gt;&lt;p&gt;In this announcement, I&amp;#39;ll describe how to set up the DevExpress MCP server across multiple IDEs, configure AI Assistants to work with our MCP server, and offer guidance on maximizing the benefits of AI-powered documentation access.&lt;/p&gt;

&lt;h2&gt;Why Use the DevExpress Documentation MCP Server?&lt;/h2&gt;

&lt;p&gt;Traditional documentation workflows require constant context switch — you need to leave your IDE, search through docs and/or Google, and manually piece together solutions found in different sources. The DevExpress Documentation MCP server eliminates this friction by:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Contextual help&lt;/strong&gt;: Ask questions about DevExpress components and get targeted answers with code examples retrieved from our documentation&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Intelligent search&lt;/strong&gt;: Search our entire documentation database (with more than 300,000 help topics)&amp;nbsp;using natural language&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Real-time documentation access&lt;/strong&gt;: Supply up-to-date information directly to your AI assistant&amp;#39;s context&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Seamless integration&lt;/strong&gt;: Thanks to the MCP protocol, you can leverage this capability when using GitHub Copilot&amp;#39;s Agent Mode and other MCP-compatible tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are just a few examples of what you can accomplish by delegating development tasks to AI coding agents powered by our Documentation MCP server:&lt;/p&gt;

&lt;h4&gt;Desktop Platforms&lt;/h4&gt;
&lt;ul&gt;
    &lt;li&gt;Create a WPF Window or Windows Form with a Ribbon, file menu actions, and DevExpress Grid controls.&lt;/li&gt;
    &lt;li&gt;Create a master-detail report mockup showing orders and line items from an EF Core data source directly in the DevExpress Visual Studio Report Designer.&lt;/li&gt;
    &lt;li&gt;Create a new Delphi app with our VCL components and display a report viewer with a single button click.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Web Platforms&lt;/h4&gt;
&lt;ul&gt;
    &lt;li&gt;Add a new Razor Page with our Blazor Grid, complete with editing capabilities and bound to a large data source.&lt;/li&gt;
    &lt;li&gt;Build a responsive dashboard page with range selectors, multiple chart types, and toolbar controls — or design a fully custom edit form with validation using our DevExtreme product suite (React/Angular/Vue/jQuery).&lt;/li&gt;
    &lt;li&gt;Create a DevExtreme-powered React or Angular web application using &lt;a target="_blank" href="https://js.devexpress.com/Templates/UITemplates/"&gt;Application Templates&lt;/a&gt; with a single prompt.&lt;/li&gt;
    &lt;li&gt;Integrate the DevExpress Report Viewer into an ASP.NET Core application.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;File and Document APIs &amp;amp; Cross-Platform App Framework&lt;/h4&gt;
&lt;ul&gt;
    &lt;li&gt;Generate Word mail merge documents with rich text formatting using our Document Processing APIs.&lt;/li&gt;
    &lt;li&gt;Create spreadsheets with calculated totals and summaries using our Spreadsheet APIs.&lt;/li&gt;
    &lt;li&gt;Generate business classes with proper data modeling attributes for XAF applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;And much more...&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;At present, our Documentation MCP server provides AI assistants with access to documentation for the last two major versions (&lt;strong&gt;v24.2&lt;/strong&gt; and &lt;strong&gt;v25.1)&lt;/strong&gt;&amp;nbsp;via separate endpoints.&lt;/p&gt;
&lt;p&gt;The DevExpress Documentation MCP server offers the following &lt;strong&gt;tools&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;devexpress_docs_search&lt;/strong&gt;: Performs semantic search&amp;nbsp;through the documentation database and returns the top 5 matches for a user query&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;devexpress_docs_get_content&lt;/strong&gt;: Allows agents to download complete help topics by URL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, our MCP server includes a built-in &lt;strong&gt;prompt&lt;/strong&gt; (&lt;code&gt;dxdocs.devexpress_docs_query_workflow&lt;/code&gt;) accessible via &lt;code&gt;/&lt;/code&gt; in compatible coding assistants. This prompt guides the AI agent through the proper workflow and constraints for DevExpress documentation queries. &lt;/p&gt;
&lt;p&gt;The server operates exclusively over the Streamable HTTP protocol. If you’re familiar with MCP, simply add the following endpoints to your AI assistant’s configuration and give it a try:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json"&gt;{
  &amp;quot;servers&amp;quot;: {
    &amp;quot;dxdocs&amp;quot;: {
      &amp;quot;url&amp;quot;: &amp;quot;https://api.devexpress.com/mcp/docs&amp;quot;,
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;
    },
    &amp;quot;dxdocs24_2&amp;quot;: {
      &amp;quot;url&amp;quot;: &amp;quot;https://api.devexpress.com/mcp/docs?v=24.2&amp;quot;,
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
    &lt;a href="https://community.devexpress.com/blogs/news/2025/mcp/mcp.json" target="_blank" class="Button Orange"&gt;DOWNLOAD THE MCP.JSON FILE&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;If you are not familiar with MCP, the following sections of this blog post list&amp;nbsp;step-by-step setup/config instructions for the&amp;nbsp;DevExpress MCP server across multiple&amp;nbsp;IDEs, including Visual Studio, VS Code, and JetBrains Rider.&lt;/p&gt;

&lt;h2&gt;Using the DevExpress MCP Server&lt;/h2&gt;

&lt;h3&gt;Basic Usage Pattern&lt;/h3&gt;

&lt;ol&gt;
    &lt;li&gt;&lt;strong&gt;Open your AI assistant&lt;/strong&gt; in your IDE&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Use Chat mode&lt;/strong&gt; to find answers to your questions&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Use Agent Mode&lt;/strong&gt;&amp;nbsp;with the MCP server for code generation&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;When asking DevExpress-related questions in Agent Mode, &lt;/strong&gt;add the &amp;quot;&lt;strong&gt;Use dxdocs&lt;/strong&gt;&amp;quot; (or &amp;quot;&lt;strong&gt;Use dxdocs24_2&lt;/strong&gt;&amp;quot;) phrase to the end of your prompt to ensure the MCP server is invoked. Alternatively, use the built-in prompt.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Approve tool execution&lt;/strong&gt; when prompted&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Review the code generated by the agent and examine comprehensive&amp;nbsp;responses&lt;/strong&gt; with code examples and documentation links&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;General Usage Recommendations for AI-Assisted Code Development&lt;/h3&gt;

&lt;p&gt;To maximize the effectiveness of AI-powered development tools, it&amp;#39;s essential to approach them with the right strategy and expectations. Start by understanding the fundamentals — familiarize yourself with how large language models work and what makes different AI coding tools unique. Think of your AI assistant as a new teammate: give it detailed context, clearly explain what you need, and don’t be afraid to write long, precise prompts.&lt;/p&gt;
&lt;p&gt;For complex tasks, first research best practices and architectural approaches using AI&amp;#39;s Chat or Ask mode. Once you&amp;#39;ve created a solid plan, delegate the implementation to the AI agent with clear, specific instructions. Always request that the coding assistant ask clarifying questions before starting implementation if anything is unclear. Then, break down complex tasks into smaller, manageable pieces. Do not expect AI to handle multiple abstraction layers simultaneously.&lt;/p&gt;
&lt;p&gt;Different AI models have different strengths — some excel at deep reasoning and problem-solving, others at rapid code generation. Experiment to see which works best for each task&amp;nbsp;and choose the best model instead of cutting corners with weaker options: the quality compounds and impacts the effectiveness of all other practices.&lt;/p&gt;

&lt;p&gt;Keep your existing codebase clean and well-documented, as AI assistants perform significantly better when they can reference clear and consistent patterns rather than contradictory code. When asking questions, explicitly include relevant source code files to provide  necessary context.&lt;/p&gt;
&lt;p&gt;Most importantly, always review&amp;nbsp;AI-generated output: check for architectural problems, security vulnerabilities, and adherence to project standards. Ultimately, you are fully responsible for all code committed to your repository.&lt;/p&gt;
&lt;p&gt;
And last, but not least: remember that AI cannot replace domain knowledge — if requirements or implementation strategy are unclear, AI won&amp;#39;t help much beyond completing simple tasks.
&lt;/p&gt;
&lt;p&gt;As it relates to DevExpress components and APIs, we identified multiple practices or prompt instructions that can help you get the most out of  AI Assistants and our MCP server:&lt;/p&gt;

&lt;ol&gt;
    &lt;li&gt;&lt;strong&gt;Be specific&lt;/strong&gt; about the DevExpress component you&amp;#39;re working with&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Include &amp;quot;Use dxdocs&amp;quot;&lt;/strong&gt; in your queries to force MCP tool usage&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Ask follow-up questions&lt;/strong&gt; to dive deeper into specific aspects&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Request code examples&lt;/strong&gt; when you need implementation guidance&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Ask about best practices&lt;/strong&gt; for component configuration and usage&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Request the use of public APIs&lt;/strong&gt; and adherence to established themes and style guidelines, instead of relying on custom solutions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For instance, the instructions below help AI assistants concentrate on designer files and leverage the &lt;code&gt;InitializeComponent&lt;/code&gt; method body in Windows Forms applications (to address UI generation tasks):&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;i&gt;Use designer files for UI layout. All form and control layout code must go in the designer.cs file. Do not write manual layout code in the main .cs file unless you are dynamically modifying the UI at runtime&lt;/i&gt;&lt;/li&gt;
    &lt;li&gt;&lt;em&gt;Initialize and configure WinForms controls within the InitializeComponent method call. Set properties such as Dock, Anchor, LookAndFeel, and Appearance within InitializeComponent rather than in event handlers&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Supported IDEs:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Visual Studio 2022 (version 17.14 or later)&lt;/li&gt;
    &lt;li&gt;Visual Studio Code&lt;/li&gt;
    &lt;li&gt;Cursor IDE&lt;/li&gt;
    &lt;li&gt;JetBrains Rider 2025.1+&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Coding Assistants:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;GitHub Copilot&lt;/li&gt;
    &lt;li&gt;JetBrains AI Assistant&lt;/li&gt;
    &lt;li&gt;...or other MCP-compatible AI assistants (such as &lt;strong&gt;Claude&lt;/strong&gt; or &lt;strong&gt;Claude Code&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since technology evolves rapidly and newer releases often include important fixes,&amp;nbsp;&lt;span&gt;I recommend using the latest versions of your IDE and plugins.&lt;/span&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;Setup Guide&lt;/h2&gt;

&lt;h3&gt;Step 1: Enable Agent Mode in Your IDE&lt;/h3&gt;

&lt;p&gt;The DevExpress Documentation MCP server works with AI assistants that support &lt;strong&gt;agent&lt;/strong&gt; mode. In this mode, AI Assistants use the MCP server to connect to external tools and data sources. This guide lists setup steps for &lt;strong&gt;GitHub&lt;/strong&gt; &lt;strong&gt;Copilot&lt;/strong&gt;.&lt;/p&gt;
&lt;h4&gt;Visual Studio&lt;/h4&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;strong&gt;Update &lt;/strong&gt; Visual Studio 2022 to at least v17.14.12.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Enable Agent Mode. &lt;/strong&gt;Go to &lt;strong&gt;Tools&lt;/strong&gt; &amp;gt; &lt;strong&gt;Options&lt;/strong&gt; &amp;gt; &lt;strong&gt;GitHub&lt;/strong&gt; &amp;gt; &lt;strong&gt;Copilot &lt;/strong&gt;and activate the &amp;quot;Enable MCP server integration in agent mode&amp;quot; and &amp;quot;Enable Agent mode in the chat pane&amp;quot; options:&lt;/li&gt;
&lt;/ol&gt;
&lt;img src="https://community.devexpress.com/blogs/news/2025/mcp/devexpress-mcp-enable-copilot-agent-in-vs.png" alt="Visual Studio — Enable Agent Mode" style="width:1544px;height:1020px;"&gt;
&lt;p&gt;Please refer to the following help topic for additional information:&amp;nbsp;&lt;a target="_blank" href="https://learn.microsoft.com/en-us/visualstudio/ide/copilot-agent-mode?view=vs-2022"&gt;Microsoft&amp;#39;s Agent Mode documentation&lt;/a&gt;.&lt;/p&gt;    
&lt;h4&gt;VS Code&lt;/h4&gt;
&lt;p&gt;To get started with GitHub Copilot&amp;#39;s agent mode, install or update the &lt;a href="https://marketplace.visualstudio.com/items?itemName=GitHub.copilot" target="_blank" title="GitHub Copilot extension"&gt;GitHub Copilot extension&lt;/a&gt;. Agent mode is active&amp;nbsp;by default in recent versions of VS Code, so you do not&amp;nbsp;need to configure this setting. To access agent mode, open the &lt;strong&gt;Chat&lt;/strong&gt; view and sign in to your GitHub account. Select &lt;strong&gt;Agent&lt;/strong&gt;&amp;nbsp;from the &lt;strong&gt;Chat&lt;/strong&gt; mode dropdown. For  detailed setup instructions,   refer to the &lt;a target="_blank" href="https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode"&gt;VS Code Agent Mode Guide&lt;/a&gt;.&lt;/p&gt;&lt;img src="https://community.devexpress.com/blogs/news/2025/mcp/devexpress-mcp-enable-copilot-agent-in-vscode_callout_1.png" alt="VSCode — Enable Agent Mode" style="width:1560px;height:1092px;"&gt;

&lt;h4&gt;Cursor&lt;/h4&gt;
&lt;p&gt;In the most recent versions of the Cursor IDE, you don&amp;#39;t need to activate Agent mode. &lt;span&gt;Simply access the chat interface with&amp;nbsp;agent capabilities. For additional information, refer to Cursor&amp;#39;s&amp;nbsp;&lt;/span&gt;&lt;a href="https://docs.cursor.com/en/agent/overview" target="_blank" title="Agent"&gt;Agent&lt;/a&gt; documentation.&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;JetBrains Rider Setup&lt;/h4&gt;
&lt;p&gt;To set up AI assistance in JetBrains Rider, you&amp;#39;ll need to update to Rider 2025.1 or later. Check that the AI Assistant plugin is&amp;nbsp;already installed and install if necessary.&amp;nbsp;For detailed guidance, review&amp;nbsp;the following JetBrains help topic:&amp;nbsp;&lt;a href="https://www.jetbrains.com/help/ai-assistant/installation-guide-ai-assistant.html" target="_blank" title="JetBrains Rider Documentation"&gt;AI Assistant Installation&lt;/a&gt;. Alternatively, you can install the &lt;a href="https://plugins.jetbrains.com/plugin/17718-github-copilot" target="_blank" title="GitHub Copilot Plugin for JB Rider"&gt;GitHub Copilot Plugin&lt;/a&gt; from the &lt;strong&gt;JetBrains Marketplace&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Step 2: Configure the DevExpress MCP Server&lt;/h3&gt;
&lt;p&gt;Now we&amp;#39;ll add the DevExpress documentation MCP server to your IDE configuration. MCP servers can be configured through workspace settings, user settings, or direct installation methods.&lt;/p&gt;
&lt;h4&gt;Visual Studio&lt;/h4&gt;
 

&lt;p&gt;Create the MCP configuration file:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Navigate to your user profile directory: &lt;code&gt;%USERPROFILE%&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;Paste the following MCP Server configuration code to a new file named&amp;nbsp;&lt;code&gt;.mcp.json&lt;/code&gt;:&lt;/li&gt;
    &lt;pre&gt;&lt;code class="language-json"&gt;{
    &amp;quot;servers&amp;quot;: {
    	&amp;quot;dxdocs&amp;quot;: {
    		&amp;quot;url&amp;quot;: &amp;quot;https://api.devexpress.com/mcp/docs&amp;quot;,
    		&amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;
    	}
    },
    &amp;quot;inputs&amp;quot;: []
}&lt;/code&gt;&lt;/pre&gt;
&lt;/ul&gt;
&lt;p&gt;Refer to the following help topic for more information: &lt;a href="https://learn.microsoft.com/en-us/visualstudio/ide/mcp-servers?view=vs-2022" target="_blank" title="Use MCP servers in Visual Studio"&gt;Use MCP servers&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;VS Code&lt;/h4&gt;
&lt;p&gt;Use the following link for one-click installation, or proceed with the manual setup.&lt;/p&gt; 
&lt;a target="_blank" href="https://insiders.vscode.dev/redirect/mcp/install?name=dxdocs&amp;amp;config=%7B%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fapi.devexpress.com%2Fmcp%2Fdocs%22%7D"&gt;&lt;img src="https://img.shields.io/badge/VS_Code-Install_DevExpress_Docs_MCP-0098FF?style=flat-square&amp;amp;logo=visualstudiocode&amp;amp;logoColor=ffffff" alt="Install DevExpress MCP Server in VS Code"&gt;&lt;/a&gt;
&lt;p&gt;If you prefer manual setup, you can use either a personal or shared configuration. To configure the server at the workspace level (and share the configuration with your team), paste the following code into a new file: &lt;code&gt;project/.vscode/mcp.json&lt;/code&gt;.
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json"&gt;{
  &amp;quot;servers&amp;quot;: {
    &amp;quot;dxdocs&amp;quot;: {
      &amp;quot;url&amp;quot;: &amp;quot;https://api.devexpress.com/mcp/docs&amp;quot;,
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;
    }
  },
  &amp;quot;inputs&amp;quot;: []
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
For personal&amp;nbsp;configuration, open the &lt;strong&gt;Command Palette&lt;/strong&gt; using &lt;code&gt;Ctrl+Shift+P&lt;/code&gt; on Windows/Linux or &lt;code&gt;⌘+Shift+P&lt;/code&gt; on Mac. Run the &amp;quot;&lt;strong&gt;MCP: Add Server&lt;/strong&gt;&amp;quot; command and complete the setup wizard to add the DevExpress MCP server.&lt;/p&gt;
&lt;img src="https://community.devexpress.com/blogs/news/2025/mcp/devexpress-mcp-add-mcp-in-vscode.png" alt="VSCode — Add a New MCP Server" style="width:1560px;height:1092px;"&gt;
&lt;p&gt;For additional information about MCP server setup in VS Code, refer to the following help topic: &lt;a href="https://code.visualstudio.com/docs/copilot/chat/mcp-servers" target="_blank" title="Use MCP servers in VS Code"&gt;Use MCP servers in VS Code&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Cursor&lt;/h4&gt;
 
&lt;p&gt;You can use our pre-configured script or set up the MCP Server manually. To apply the pre-configured script, use the following one-click installation link:&lt;/p&gt;&lt;a target="_blank" href="https://cursor.com/en/install-mcp?name=dxdocs&amp;amp;config=eyJ1cmwiOiJodHRwczovL2FwaS5kZXZleHByZXNzLmNvbS9tY3AvZG9jcyIsInR5cGUiOiJodHRwIn0%3D"&gt;&lt;img src="https://cursor.com/deeplink/mcp-install-dark.svg" alt="Add dxdocs MCP server to Cursor" height="32"&gt;&lt;/a&gt;
&lt;p&gt;For manual configuration, create a new file in your preferred configuration location:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;code&gt;project/.cursor/mcp.json&lt;/code&gt; for project-specific configuration&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;home_directory/.cursor/mcp.json&lt;/code&gt; for global configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To learn more about Model Context Protocol support in Cursor, navigate to the following help topic: &lt;a href="https://docs.cursor.com/en/context/mcp#using-mcp-json" target="_blank" title="Connect external tools and data sources to Cursor using MCP"&gt;Connect external tools and data sources to Cursor using MCP&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Paste the following code into the configuration file:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-json"&gt;{
  &amp;quot;mcpServers&amp;quot;: {
    &amp;quot;dxdocs&amp;quot;: {
      &amp;quot;url&amp;quot;: &amp;quot;https://api.devexpress.com/mcp/docs&amp;quot;,
      &amp;quot;type&amp;quot;: &amp;quot;sse&amp;quot;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alternatively, use Cursor&amp;#39;s &lt;strong&gt;MCP Settings&lt;/strong&gt; UI: navigate to the &lt;strong&gt;Tools &amp;amp; Integrations&lt;/strong&gt; section, click &lt;strong&gt;New MCP Server&lt;/strong&gt;,&amp;nbsp;and enter  server details.&lt;/p&gt;
&lt;img src="https://community.devexpress.com/blogs/news/2025/mcp/devexpress-mcp-enable-mcp-in-cursor.png" alt="Cursor — DevExpress MCP Server Tools" style="width:1400px;height:608px;"&gt;
&lt;p&gt;Refer to the following help topic for additional information: &lt;a href="https://docs.cursor.com/en/context/mcp" target="_blank" title="Model Context Protocol (MCP)"&gt;Model Context Protocol (MCP)&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;JetBrains Rider&lt;/h4&gt;
&lt;p&gt;Add a new MCP server as detailed in the following JetBrains Rider help topic: &lt;a target="_blank" href="https://www.jetbrains.com/help/ai-assistant/mcp.html#connect-to-an-mcp-server"&gt;Model Context Protocol&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note that at present, JetBrains Rider can only use&amp;nbsp;&lt;code&gt;stdio&lt;/code&gt; protocol with MCP servers. To set up DevExpress MCP Server, follow the documented&amp;nbsp;&lt;a target="_blank" href="https://www.jetbrains.com/help/ai-assistant/mcp.html#workaround-for-remote-servers"&gt;workaround&lt;/a&gt; for remote servers.&lt;/p&gt;

&lt;p&gt;If you use the &lt;strong&gt;GitHub Copilot Chat&lt;/strong&gt; plugin, change the chat mode to &lt;strong&gt;Agent&lt;/strong&gt; and add new tools as described in the &lt;a target="_blank" href="https://docs.github.com/en/copilot/how-tos/provide-context/use-mcp/extend-copilot-chat-with-mcp?tool=jetbrains"&gt;GitHub documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Step 3: Verify DevExpress MCP Server Connection&lt;/h3&gt;
&lt;h4&gt;Visual Studio&lt;/h4&gt;
&lt;p&gt;To verify the connection in Visual Studio, open the &lt;strong&gt;GitHub Copilot Chat&lt;/strong&gt; pane and click the &lt;strong&gt;Tools&lt;/strong&gt; icon (🛠️) to view available MCP servers. Verify that the list contains DevExpress tools.&lt;/p&gt;
&lt;img src="https://community.devexpress.com/blogs/news/2025/mcp/devexpress-mcp-tools-in-vs.png" alt="Visual Studio GitHub Copilot Chat — DevExpress MCP Server Tools" style="width:510px;height:830px;"&gt;
&lt;h4&gt;VS Code&lt;/h4&gt;
&lt;p&gt;Open the&amp;nbsp;&lt;strong&gt;Github Copilot Chat&lt;/strong&gt; pane using the icon in the title bar. Use the mode selector to activate&amp;nbsp;&lt;strong&gt;Agent Mode&lt;/strong&gt;. Click the &lt;strong&gt;Tools&lt;/strong&gt; icon (🛠️) to view available MCP servers and confirm that the server list contains &amp;quot;dxdocs&amp;quot; and associated tools.&lt;/p&gt;
&lt;img src="https://community.devexpress.com/blogs/news/2025/mcp/devexpress-mcp-tools-in-vscode-enabled.png" alt="Visual Studio Code GitHub Copilot Chat — DevExpress MCP Server Tools Enabled" style="width:1560px;height:1092px;"&gt;
&lt;h4&gt;Cursor&lt;/h4&gt;
&lt;p&gt;Open &lt;strong&gt;Settings&lt;/strong&gt; and navigate to &lt;strong&gt;Tools &amp;amp;  Integration&lt;/strong&gt;. Check the &amp;quot;dxdocs&amp;quot; MCP server status: the slider next to the server name should be green (indicates a successful connection).&lt;/p&gt;
&lt;h4&gt;JetBrains Rider&lt;/h4&gt;
&lt;p&gt;In JetBrains Rider, open the AI Assistant and type &lt;code&gt;/&lt;/code&gt; to see available commands. Verify that the DevExpress MCP tools appear in the command list:&lt;/p&gt;&lt;img src="https://community.devexpress.com/blogs/news/2025/mcp/devexpress-mcp-tools-in-rider-assistant.png" alt="JetBrains Rider — AI Assistant — MCP Tools" style="width:740px;height:836px;"&gt;&lt;p&gt; If using the &lt;strong&gt;GitHub Copilot Chat&lt;/strong&gt; plugin, change the chat mode to &lt;strong&gt;Agent&lt;/strong&gt;, click the &lt;strong&gt;Tools&lt;/strong&gt; icon (🛠️), and ensure that DevExpress MCP tools are selected:&lt;/p&gt;
&lt;img src="https://community.devexpress.com/blogs/news/2025/mcp/devexpress-mcp-tools-in-rider-enabled.png" alt="JetBrains Rider — Github Copilot Chat — MCP Tools" style="width:1416px;height:976px;"&gt;
&lt;h3&gt;Step 4: Optimize Your AI Assistant with Custom Instructions&lt;/h3&gt;
&lt;p&gt;For best results when using the DevExpress documentation MCP server, define custom instructions to guide your AI assistant on how to use the tools effectively.&lt;/p&gt;
&lt;h4&gt;Use The Predefined DevExpress MCP Server Prompt&lt;/h4&gt;
&lt;p&gt;To activate the predefined prompt:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Run the following command in the chat window:&lt;code&gt;/mcp.dxdocs.devexpress_docs_query_workflow&lt;/code&gt;.&lt;/li&gt;
    &lt;li&gt;Specify your question and submit the request.&lt;/li&gt;
&lt;/ul&gt;
&lt;img src="https://community.devexpress.com/blogs/news/2025/mcp/devexpress-mcp-vscode-choose-prompt.png" alt="Visual Studio Code GitHub Copilot Chat — Prompt"&gt;
&lt;h4&gt;Custom Instructions — VS Code, Visual Studio, and JetBrains Rider (GitHub Copilot)&lt;/h4&gt;
&lt;p&gt;Add a &lt;code&gt;.github/copilot-instructions.md&lt;/code&gt; file to your solution directory. Below is a sample instructions file that you can customize and extend based on your requirements:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-markup"&gt;---
description: &amp;#39;Answer questions about the DevExpress UI Components and their API using the dxdocs server&amp;#39;
---

You are a .NET/JavaScript programmer and DevExpress products expert.

Your task is to answer questions about DevExpress components and their APIs using dxdocs MCP server tools.

When replying to **ANY** question about DevExpress components, use the dxdocs server to construct your answer.

## Workflow:
1. **Call devexpress_docs_search** to obtain help topics related to the user&amp;#39;s question
2. **Call devexpress_docs_get_content** to fetch and read the most relevant help topics  
3. **Reflect on the obtained content** and how it relates to the question
4. **Provide a comprehensive answer** based solely on retrieved information

## Constraints:
- **Use devexpress_docs_search only once** per question to avoid redundant queries
- **Answer questions based solely** on information obtained from MCP server tools
- If relevant code examples are available in documentation, **include those code examples**
- **Reference specific DevExpress controls and properties** mentioned in the docs
- If a user specifies a version (e.g., v24.2 or 24.2), invoke corresponding MCP server tools (e.g., dxdocs24_2)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Learn more about GitHub Copilot custom instructions in the following help topics:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a target="_blank" href="https://docs.github.com/en/copilot/how-tos/custom-instructions/adding-repository-custom-instructions-for-github-copilot?tool=vscode"&gt;VS Code Custom Instructions&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target="_blank" href="https://docs.github.com/en/copilot/how-tos/custom-instructions/adding-repository-custom-instructions-for-github-copilot?tool=visualstudio"&gt;Visual Studio Custom Instructions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Cursor&lt;/h4&gt;

&lt;p&gt;Navigate to the &lt;code&gt;Settings &amp;gt; Rules &amp;amp; Memories&lt;/code&gt; window. Run the &lt;code&gt;Add Rule&lt;/code&gt; command and specify a rule with similar content. For additional information about &lt;strong&gt;Rules&lt;/strong&gt; in Cursor IDE, refer to the following help topic: &lt;a target="_blank" href="https://docs.cursor.com/en/context/rules"&gt;Rules&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;JetBrains Rider (AI Assistant)&lt;/h4&gt;

&lt;p&gt;Create a custon propmt in the AI Assistant chat as described in the following help topic: &lt;a target="_blank" href="https://www.jetbrains.com/help/ai-assistant/prompt-library.html"&gt;JetBrains Rider – Add and customize prompts&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Advanced Features&lt;/h3&gt;

&lt;h4&gt;Custom Chat Modes (VS Code Only)&lt;/h4&gt;

&lt;p&gt;VS Code supports custom chat modes for specialized workflows. Chat modes are predefined configurations that allow you to tailor AI chat behavior in Visual Studio Code for specific tasks. You can switch between chat modes at any time in the Chat view, based on&amp;nbsp;what you wish to accomplish.&lt;/p&gt;

&lt;div class="Note"&gt;
    &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Custom chat modes are available for VS Code version 1.101 and are currently in preview.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;A chat mode file is a Markdown file with the &lt;code&gt;.chatmode.md&lt;/code&gt; suffix that contains:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Front Matter Metadata:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;code&gt;description&lt;/code&gt;: Brief description displayed as placeholder text and in hover tooltips&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;tools&lt;/code&gt;: List of available tools or tool sets for this mode&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;model&lt;/code&gt;: Specific AI model to use (optional)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Body Content:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Detailed instructions and guidelines for the AI to follow&lt;/li&gt;
    &lt;li&gt;References to instruction files using Markdown links&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Create a DevExpress Chat Mode&lt;/h4&gt;

&lt;ol&gt;
    &lt;li&gt;Open the Command Palette:
        &lt;ul&gt;
            &lt;li&gt;Windows/Linux: &lt;code&gt;Ctrl+Shift+P&lt;/code&gt;&lt;/li&gt;
            &lt;li&gt;macOS: &lt;code&gt;Cmd+Shift+P&lt;/code&gt;&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;Run the command: &lt;code&gt;Chat: New Mode File&lt;/code&gt;. Alternatively, select &amp;quot;Configure Modes&amp;quot; from the chat mode dropdown&lt;/li&gt;
    &lt;li&gt;Choose the location: Select workspace or user profile&lt;/li&gt;
    &lt;li&gt;Enter a chat mode name (e.g., DevExpress Agent Mode)&lt;/li&gt;
    &lt;li&gt;Configure the chat mode file.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="Note"&gt;
    &lt;p&gt;By default, VS Code looks for workspace chat mode files in the &lt;code&gt;.github/chatmodes&lt;/code&gt; folder.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Here&amp;#39;s a custom DX Agent Chat mode that you can tailor to your needs. The chat mode description is inspired by the &lt;a target="_blank" href="https://gist.github.com/burkeholland/88af0249c4b6aff3820bf37898c8bacf"&gt;Beast Mode&lt;/a&gt; prompt:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-markup"&gt;---
description: &amp;#39;DevExpress development assistant using MCP server integration&amp;#39;
tools: [&amp;#39;codebase&amp;#39;, &amp;#39;usages&amp;#39;, &amp;#39;think&amp;#39;, &amp;#39;problems&amp;#39;, &amp;#39;changes&amp;#39;, &amp;#39;terminalSelection&amp;#39;, &amp;#39;terminalLastCommand&amp;#39;, &amp;#39;fetch&amp;#39;, &amp;#39;searchResults&amp;#39;, &amp;#39;githubRepo&amp;#39;, &amp;#39;editFiles&amp;#39;, &amp;#39;search&amp;#39;, &amp;#39;runCommands&amp;#39;, &amp;#39;runTasks&amp;#39;, &amp;#39;dxdocs&amp;#39;, &amp;#39;microsoft-docs&amp;#39;]
model: &amp;#39;Claude Sonnet 4&amp;#39;
---
You are a .NET/JavaScript programmer and DevExpress products expert.

Your task is to answer questions about DevExpress components and their APIs, and assist in application development. For **ANY** question about DevExpress components, use the dxdocs server to construct your answer.

## Workflow:

1. Understand the user&amp;#39;s question and identify the relevant development platform, DevExpress component or API they are asking about.
   - If the question is about a specific DevExpress control, property, or feature, make sure to note it.
   - If the question is about a general concept or best practice, try to relate it to a specific DevExpress component or feature.  
   - Think critically about what is required to answer the question effectively, considering the context and the user&amp;#39;s needs.
   - If the question is vague or lacks detail, ask for clarification to ensure you provide the most relevant information.
   - Use sequential reasoning to break down complex questions into manageable parts, focusing on the specific DevExpress components or APIs involved.
   - Develop a clear, step-by-step plan to address the question, ensuring you cover all necessary aspects related to DevExpress components and their APIs.
   - Implement code changes incrementally, make small, testable changes, and verify each step to ensure correctness.

2. Tool Usage:
    1. **Call devexpress_docs_search** to obtain help topics related to the user&amp;#39;s question
    2. **Call devexpress_docs_get_content** to fetch and read the most relevant help topics
    3. **In case you receive the document not found error**, try to search again with a different query or use the **fetch** tool to get the content directly from the DevExpress documentation website
    4. **Reflect on the obtained content** and how it relates to the question
    5. **Provide a comprehensive answer** based on the retrieved information

## Guidelines:

- **Use devexpress_docs_search only once** per question to avoid redundancy
- **Base answers solely** on information from MCP server tools
- **Always include code examples** when available in documentation
- **Reference specific DevExpress controls and properties** mentioned in docs
- **Share links to relevant documentation** for further reading
- **Make incremental, testable changes** when implementing solutions

## Memory:

You have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you&amp;#39;ll need to create it.

When creating a new memory file, you MUST include the following front matter at the top of the file:

---
applyTo: &amp;#39;**&amp;#39;
---

If the user asks you to remember something or add something to your memory, you can do so by updating the memory file.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For additional information (creating and customizing custom chat modes) see:&amp;nbsp;&lt;a target="_blank" href="https://code.visualstudio.com/docs/copilot/chat/chat-modes"&gt;VS Code Chat Modes&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Troubleshooting Common Issues&lt;/h2&gt;

&lt;h3&gt;MCP Server Not Appearing&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptoms&lt;/strong&gt;: DevExpress tools don&amp;#39;t appear in the AI interface&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solutions&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;strong&gt;Verify configuration file syntax&lt;/strong&gt; — JSON must be valid&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Restart your IDE&lt;/strong&gt;  after configuration changes&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Check the server URL&lt;/strong&gt; — ensure it&amp;#39;s &lt;code&gt;https://api.devexpress.com/mcp/docs&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Confirm Agent Mode is enabled&lt;/strong&gt; in your IDE settings&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;Tool Calls Failing Silently&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptoms&lt;/strong&gt;: The AI assistant doesn&amp;#39;t use DevExpress tools even when requested&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solutions&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;strong&gt;Add &amp;quot;Use dxdocs&amp;quot; explicitly&lt;/strong&gt; to your queries&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Check tool permissions&lt;/strong&gt; in assistant settings&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Verify network connectivity&lt;/strong&gt; to the DevExpress MCP server&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Restart the MCP server connection&lt;/strong&gt; through IDE settings&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;Performance Issues&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptoms&lt;/strong&gt;: Slow responses or timeouts&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solutions&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;strong&gt;Check network connection&lt;/strong&gt; — ensure stable internet connectivity&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Reduce query complexity&lt;/strong&gt; — break complex questions into smaller parts&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Monitor rate limits&lt;/strong&gt; — avoid excessive requests in short timeframes&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Try different AI models&lt;/strong&gt; — switch between available models if experiencing issues&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Additional Resources&lt;/h2&gt;

&lt;h3&gt;Official Documentation&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a target="_blank" href="https://modelcontextprotocol.io/overview"&gt;Model Context Protocol Quickstart Guide&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target="_blank" href="https://www.anthropic.com/news/model-context-protocol"&gt;Anthropic&amp;#39;s MCP Introduction&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;Microsoft&amp;#39;s MCP Setup Guides for &lt;a target="_blank" href="https://code.visualstudio.com/docs/copilot/chat/mcp-servers"&gt;VS Code&lt;/a&gt; and &lt;a target="_blank" href="https://learn.microsoft.com/en-us/visualstudio/ide/mcp-servers?view=vs-2022"&gt;Visual Studio&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target="_blank" href="https://docs.cursor.com/context/model-context-protocol"&gt;Cursor MCP Documentation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target="_blank" href="https://www.jetbrains.com/help/ai-assistant/mcp.html"&gt;JetBrains MCP Guide&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target="_blank" href="https://github.com/modelcontextprotocol/servers"&gt;Official MCP Servers Repository&lt;/a&gt; — Browse other available MCP servers&lt;/li&gt;
    &lt;li&gt;&lt;a target="_blank" href="https://github.com/mcp"&gt;GitHub MCP Registry&lt;/a&gt; — GitHub curated directory of MCP servers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Video Tutorials&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a target="_blank" href="https://www.youtube.com/watch?v=oPFecZHBCkg"&gt;Visual Studio MCP Overview&lt;/a&gt; — Comprehensive setup walkthrough&lt;/li&gt;
    &lt;li&gt;&lt;a target="_blank" href="https://www.youtube.com/watch?v=Y-2mUUB_I1c"&gt;VS Code MCP Usage&lt;/a&gt; — Practical examples and tips&lt;/li&gt;
    &lt;li&gt;&lt;a target="_blank" href="https://www.youtube.com/watch?v=iS25RFups4A"&gt;Advanced VS Code MCP&lt;/a&gt; — Deep dive into advanced features&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Related Tools&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Microsoft .NET Docs MCP Server&lt;/strong&gt;: &lt;code&gt;https://learn.microsoft.com/api/mcp&lt;/code&gt; — Helpful for general .NET development&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;&lt;a target="_blank" href="https://github.com/github/github-mcp-server"&gt;GitHub MCP Server&lt;/a&gt;&lt;/strong&gt;: Official GitHub integration for repository management&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;&lt;a target="_blank" href="https://github.com/microsoft/playwright-mcp"&gt;Playwright MCP Server&lt;/a&gt;&lt;/strong&gt;: Browser automation capabilities using Playwright&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Your Feedback Counts&lt;/h2&gt;

&lt;p&gt;We&amp;#39;ll actively develop and improve our MCP server in the coming months, and we&amp;#39;d love to hear your feedback on our current implementation.&lt;/p&gt;

&lt;h3&gt;Quick Survey&lt;/h3&gt;



&lt;div data-survey-id="f34f01eb-8230-4013-b038-f264144583ca" data-survey-auth-required="false"&gt;&lt;/div&gt;&lt;h3&gt;Share Your Experience&lt;/h3&gt;

&lt;p&gt;We&amp;#39;d love to hear about your use cases and success stories: please report issues or request features via the&amp;nbsp;&lt;a target="_blank" href="https://supportcenter.devexpress.com"&gt;DevExpress Support Center&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;What&amp;#39;s Next?&lt;/h2&gt;

&lt;p&gt;The DevExpress MCP server is just the start - We expect to introduce the following enhancements in the near future:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;Search through DevExpress Breaking Change documents to streamline/improve the upgrade process&lt;/li&gt;
    &lt;li&gt;Access to DevExpress demo source code and examples&lt;/li&gt;
    &lt;li&gt;Integration with the public community solutions database found in our Support Center&lt;/li&gt;
&lt;/ul&gt;</description>
      <pubDate>Thu, 16 Oct 2025 01:45:00 Z</pubDate>
      <dc:creator>Dmitry Tokmachev (DevExpress)</dc:creator>
    </item>
    <item>
      <guid isPermaLink="false">bd716303-653c-428d-8b8a-a7d998cde032:388242</guid>
      <link>https://community.devexpress.com/Blogs/news/archive/2025/04/21/net-aspire-xaf-blazor-custom-telemetry-service-orchestration-database-dependency.aspx</link>
      <category domain="https://community.devexpress.com/Tags/.NET">.NET</category>
      <category domain="https://community.devexpress.com/Tags/.NET+8">.NET 8</category>
      <category domain="https://community.devexpress.com/Tags/.net+9">.net 9</category>
      <category domain="https://community.devexpress.com/Tags/.net+core">.net core</category>
      <category domain="https://community.devexpress.com/Tags/ASP.NET+Core">ASP.NET Core</category>
      <category domain="https://community.devexpress.com/Tags/Aspire">Aspire</category>
      <category domain="https://community.devexpress.com/Tags/Blazor">Blazor</category>
      <category domain="https://community.devexpress.com/Tags/demo">demo</category>
      <category domain="https://community.devexpress.com/Tags/deployment">deployment</category>
      <category domain="https://community.devexpress.com/Tags/Docker">Docker</category>
      <category domain="https://community.devexpress.com/Tags/Linux">Linux</category>
      <category domain="https://community.devexpress.com/Tags/lob">lob</category>
      <category domain="https://community.devexpress.com/Tags/non-Windows">non-Windows</category>
      <category domain="https://community.devexpress.com/Tags/productivity">productivity</category>
      <category domain="https://community.devexpress.com/Tags/rad">rad</category>
      <category domain="https://community.devexpress.com/Tags/SQL+Server">SQL Server</category>
      <category domain="https://community.devexpress.com/Tags/v24.2">v24.2</category>
      <category domain="https://community.devexpress.com/Tags/Web">Web</category>
      <category domain="https://community.devexpress.com/Tags/XAF">XAF</category>
      <title>.NET Aspire Support For An XAF Blazor Project — Custom Telemetry, Service Orchestration, Database Dependency</title>
      <description>&lt;p&gt;
  In
  &lt;a href="https://community.devexpress.com/Blogs/news/archive/2025/03/25/net-aspire-support-for-an-xaf-blazor-project.aspx" target="_blank" rel="nofollow noreferrer"&gt;a recent blog post&lt;/a&gt;
  I described how an XAF Blazor project can be adjusted to
  support .NET Aspire. With a couple of changes to the startup
  logic, in both the standard XAF project template and the code
  added by the Aspire Visual Studio wizard, it became possible to
  run the XAF Blazor project as part of an Aspire orchestration -
  but it was the smallest possible orchestration, with just one
  module!
&lt;/p&gt;
&lt;p&gt;
  As promised, I will demonstrate a few more aspects of the
  Aspire based project structure. I’m leaving deployment
  considerations for a third post (watch out for it in the near
  future!), but below I’ll describe the changes I made to the
  sample project for the following three scenarios:
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    Log custom activities and metrics through Open Telemetry to
    the Aspire Dashboard
  &lt;/li&gt;
  &lt;li&gt;
    Make SQL Server a dependency which runs in a container
    coordinated by Aspire
  &lt;/li&gt;
  &lt;li&gt;
    Add an extra service to the orchestration to illustrate a
    slightly more complex application system
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  The complete sample project is available
  &lt;a href="https://github.com/oliversturm/XafAspireDemo/tree/demo-step-2" style="background-color:#ffff99;" target="_blank"&gt;in this GitHub repository&lt;/a&gt;. Based on the state I
  described in the first blog post, please read on for details of
  the new functionality.
&lt;/p&gt;
&lt;h2 id="custom-telemetry"&gt;Utilize the Open Telemetry Support for Custom Application Metrics and Activities&amp;nbsp;&lt;/h2&gt;
&lt;p&gt;
  The integration of the Aspire dashboard is one of the most
  obvious new features in many application projects, right after
  integrating Aspire. As you have seen in the first step of the
  demo project, it is easy to activate various default sources
  for tracing and metrics. After that the question quickly
  becomes: how do you use the telemetry system for your own
  needs, for logging and reporting your own metrics and
  activities?
&lt;/p&gt;
&lt;p&gt;
  As a first step, I created the file
  &lt;code&gt;XafAspireDemo.Blazor.Server/Controllers/ImportantBusinessOperationsController.cs&lt;/code&gt;, with a basic implementation of an XAF controller that
  supplies an action. This action becomes visible in the UI
  automatically, so you can use it as an interactive test
  trigger. Here’s the code:
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp" data-line-numbers="true"&gt;namespace XafAspireDemo.Blazor.Server.Controllers
{
    public class ImportantBusinessOperationsController : Controller
    {
        SimpleAction importantBusinessAction;
        IServiceProvider serviceProvider;

        public ImportantBusinessOperationsController()
        {
            importantBusinessAction = new SimpleAction(
                this,
                &amp;quot;ImportantBusinessAction&amp;quot;,
                PredefinedCategory.View
            );
            importantBusinessAction.Execute += ImportantBusinessAction_Execute;
        }

        [ActivatorUtilitiesConstructor]
        public ImportantBusinessOperationsController(IServiceProvider serviceProvider)
            : this()
        {
            this.serviceProvider = serviceProvider;
        }

        private async void ImportantBusinessAction_Execute(
            object sender,
            SimpleActionExecuteEventArgs e
        )
        {
            var logger = serviceProvider.GetRequiredService&amp;lt;
                ILogger&amp;lt;ImportantBusinessOperationsController&amp;gt;
            &amp;gt;();

            importantBusinessAction.Enabled[&amp;quot;ImportantBusinessActionRunning&amp;quot;] = false;

            logger.LogInformation(&amp;quot;ImportantBusinessAction started.&amp;quot;);

            try
            {
                // This is where we perform the magic for the important business action.
                // Run a task that waits a random time between half a second and five seconds.
                await Task.Run(() =&amp;gt;
                {
                    Thread.Sleep(new Random().Next(500, 5000));
                });
            }
            catch (Exception ex)
            {
                logger.LogError(ex, &amp;quot;ImportantBusinessAction failed.&amp;quot;);
                throw;
            }
            finally
            {
                importantBusinessAction.Enabled[&amp;quot;ImportantBusinessActionRunning&amp;quot;] = true;
            }
        }

        protected override void OnActivated()
        {
            base.OnActivated();

            var logger = serviceProvider.GetRequiredService&amp;lt;
                ILogger&amp;lt;ImportantBusinessOperationsController&amp;gt;
            &amp;gt;();
            logger.LogInformation(&amp;quot;ImportantBusinessOperationsController activated.&amp;quot;);
        }

        protected override void OnDeactivated()
        {
            var logger = serviceProvider.GetRequiredService&amp;lt;
                ILogger&amp;lt;ImportantBusinessOperationsController&amp;gt;
            &amp;gt;();
            logger.LogInformation(&amp;quot;ImportantBusinessOperationsController deactivated.&amp;quot;);

            base.OnDeactivated();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  As you can see, this code is already instrumented with some log
  output instructions. It uses the standard
  &lt;code&gt;ILogger&amp;lt;T&amp;gt;&lt;/code&gt; interface that is
  &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.ilogger-1?view=net-9.0-pp" target="_blank" rel="nofollow noreferrer"&gt;part of .NET&lt;/a&gt;, coupled with constructor injection with
  &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.iserviceprovider?view=net-9.0" target="_blank" rel="nofollow noreferrer"&gt;&lt;code&gt;IServiceProvider&lt;/code&gt;&lt;/a&gt;, which is
  &lt;a href="https://docs.devexpress.com/eXpressAppFramework/404402/app-shell-and-base-infrastructure/dependency-injection-in-xaf-applications/dependency-injection-in-controllers#constructor-injection-with-iserviceprovider-parameter-preferred-method" target="_blank" rel="nofollow noreferrer"&gt;preferred by XAF to retrieve the injected service in the
    controller implementation&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
  The logging functionality supplied by the ASP.NET Core
  infrastructure integrates with the Aspire Dashboard
  automatically. With the above changes, you can run the
  application and click the
  &lt;em&gt;Important Business Action&lt;/em&gt; button. The implementation
  disables the button for a random duration and outputs log lines
  during initialization and on startup of the interactive
  process. In the Aspire Dashboard, the Structured Logs page
  displays this output.
&lt;/p&gt;
&lt;p&gt;
  &lt;img alt="" src="https://community.devexpress.com/blogs/news/20250404-xaf-aspire-2/2025-04-04-001834@2x.png" style="width:691px;"&gt;
&lt;/p&gt;
&lt;p&gt;
  &lt;img alt="" src="https://community.devexpress.com/blogs/news/20250404-xaf-aspire-2/2025-04-04-001835@2x.png" style="width:670px;"&gt;
&lt;/p&gt;
&lt;p&gt;
  Now, in order to record Open Telemetry activities and work with
  meters, these objects need to be initialized on application
  startup, and any code that should interface with the generated
  objects must be able to retrieve them. This could be achieved
  by a global singleton implementation, for example, but in the
  demo app it makes more sense to take advantage of dependency
  injection again and let it handle the singleton aspect.
&lt;/p&gt;
&lt;p&gt;
  Here is the implementation of the class
  &lt;code&gt;XafAspireDemo.Blazor.Server.Telemetry&lt;/code&gt;:
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp" data-line-numbers="true"&gt;namespace XafAspireDemo.Blazor.Server
{
    public class Telemetry : IDisposable
    {
        public ActivitySource ActivitySource { get; }
        public Meter Meter { get; }
        public string MeterName =&amp;gt; Meter.Name;
        public Counter&amp;lt;long&amp;gt; ImportantBusinessOperationCounter { get; }
        public Histogram&amp;lt;double&amp;gt; ImportantBusinessOperationDuration { get; }

        public Telemetry(
            string serviceName = &amp;quot;XafAspireDemo.Blazor.Server&amp;quot;,
            string version = &amp;quot;1.0.0&amp;quot;
        )
        {
            ActivitySource = new ActivitySource(serviceName, version);
            Meter = new Meter(serviceName, version);

            ImportantBusinessOperationCounter = Meter.CreateCounter&amp;lt;long&amp;gt;(
                &amp;quot;important_business_operation.execution_count&amp;quot;
            );
            ImportantBusinessOperationDuration = Meter.CreateHistogram&amp;lt;double&amp;gt;(
                &amp;quot;important_business_operation.execution_duration&amp;quot;
            );
        }

        public void Dispose()
        {
            ActivitySource.Dispose();
            Meter.Dispose();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  The types &lt;code&gt;ActivitySource&lt;/code&gt;, &lt;code&gt;Meter&lt;/code&gt;,
  &lt;code&gt;Counter&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;Histogram&amp;lt;T&amp;gt;&lt;/code&gt; are
  all from the &lt;code&gt;System.Diagnostics.Metrics&lt;/code&gt; namespace.
  The class simply instantiates these on startup and disposes of
  them when the application run ends. Now you just need a few
  lines to create an instance and register it as a singleton for
  dependency injection. Of course other patterns are possible,
  but this approach is convenient for the structure of the demo.
&lt;/p&gt;
&lt;p&gt;
  This code goes in
  &lt;code&gt;XafAspireDemo.Blazor.Server/Startup.cs&lt;/code&gt;:
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp" data-line-numbers="true"&gt;    builder.AddEntityFrameworkCoreInstrumentation();
});

--&amp;gt; var telemetry = new Telemetry();
--&amp;gt; services.AddSingleton(telemetry);

--&amp;gt; services
--&amp;gt;     .AddOpenTelemetry()
--&amp;gt;     .WithTracing(tracing =&amp;gt; tracing.AddSource(&amp;quot;XafAspireDemo.Blazor.Server&amp;quot;))
--&amp;gt;     .WithMetrics(metrics =&amp;gt;
--&amp;gt;     {
--&amp;gt;         metrics.AddMeter(telemetry.MeterName);
--&amp;gt;     });

services.AddSingleton(
    typeof(Microsoft.AspNetCore.SignalR.HubConnectionHandler&amp;lt;&amp;gt;),
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  What remains is to use the new features in the sample
  controller. I added a few lines to the execution handler for
  the &lt;code&gt;ImportantBusinessAction&lt;/code&gt;:
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp" data-line-numbers="true"&gt;private async void ImportantBusinessAction_Execute(
    object sender,
    SimpleActionExecuteEventArgs e
)
{
--&amp;gt;    var telemetry = serviceProvider.GetRequiredService&amp;lt;Telemetry&amp;gt;();
    var logger = serviceProvider.GetRequiredService&amp;lt;
        ILogger&amp;lt;ImportantBusinessOperationsController&amp;gt;
    &amp;gt;();

    importantBusinessAction.Enabled[&amp;quot;ImportantBusinessActionRunning&amp;quot;] = false;

--&amp;gt;    using var activity = telemetry.ActivitySource.StartActivity(&amp;quot;ImportantBusinessAction&amp;quot;);
    logger.LogInformation(&amp;quot;ImportantBusinessAction started.&amp;quot;);

    try
    {
		...
    }
    catch (Exception ex)
    {
        logger.LogError(ex, &amp;quot;ImportantBusinessAction failed.&amp;quot;);
--&amp;gt;        activity?.SetStatus(ActivityStatusCode.Error);
--&amp;gt;        activity?.AddException(ex);
        throw;
    }
    finally
    {
--&amp;gt;        activity?.Stop();

        importantBusinessAction.Enabled[&amp;quot;ImportantBusinessActionRunning&amp;quot;] = true;

--&amp;gt;        telemetry.ImportantBusinessOperationCounter.Add(1);
--&amp;gt;        telemetry.ImportantBusinessOperationDuration.Record(
--&amp;gt;            activity.Duration.TotalMilliseconds
--&amp;gt;        );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  At the top of the method, the reference to the singleton is
  retrieved from dependency injection, just like the
  &lt;code&gt;ILogger&amp;lt;T&amp;gt;&lt;/code&gt;. An activity is started near the top
  of the method, and further code below adds details to this
  activity if an error occurs, and uses the activity’s
  &lt;code&gt;Duration&lt;/code&gt; property to figure out how long the
  process ran. The two meter elements
  &lt;code&gt;ImportantBusinessOperationCounter&lt;/code&gt; and
  &lt;code&gt;ImportantBusinessOperationDuration&lt;/code&gt; are modified to
  include details about the current run.
&lt;/p&gt;
&lt;p&gt;
  With these elements in place, the Aspire Dashboard now displays
  the new metrics and activities when the business operation is
  executed. Note that a link is also generated between a meter
  entry (for instance a duration record) and the corresponding
  activity - the Open Telemetry system is clever and handles much
  of this automatically.
&lt;/p&gt;
&lt;p&gt;
  &lt;img alt="" src="https://community.devexpress.com/blogs/news/20250404-xaf-aspire-2/2025-04-04-001836@2x.png" style="width:672px;"&gt;
&lt;/p&gt;
&lt;p&gt;
  &lt;img alt="" src="https://community.devexpress.com/blogs/news/20250404-xaf-aspire-2/2025-04-04-001837@2x.png" style="width:706px;"&gt;
&lt;/p&gt;
&lt;h2 id="sql-server-in-a-container"&gt;Add SQL Server as a Container Dependency&lt;/h2&gt;&lt;p&gt;
  One of the best things about Aspire is that it can handle
  infrastructure dependencies of your application system for you.
  There are numerous NuGet packages by now, usually named
  starting with &lt;code&gt;Aspire.Hosting.&lt;/code&gt;, which provide
  wrappers to interface with specific architectural components.
  One such component is SQL Server, and as expected the package
  &lt;code&gt;Aspire.Hosting.SqlServer&lt;/code&gt; makes this available.
&lt;/p&gt;
&lt;p&gt;
  Note that the NuGet package reference needs to be added to the
  project &lt;code&gt;XafAspire.AppHost&lt;/code&gt;, since this is where the
  SQL Server instance will be configured as part of the
  orchestration!
&lt;/p&gt;
&lt;p&gt;
  A second note: to run containers as part of an Aspire
  orchestration, you need to have a container runtime installed.
  Please check out
  &lt;a href="https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/setup-tooling?tabs=windows&amp;amp;pivots=visual-studio#container-runtime" target="_blank" rel="nofollow noreferrer"&gt;this Microsoft documentation page&lt;/a&gt;
  in case you need help with this step.
&lt;/p&gt;
&lt;p&gt;
  To declare that the orchestration requires a SQL Server
  component, and that it will be a dependency for the Blazor
  Server process, all you need are a few lines of code in the
  file &lt;code&gt;XafAspireDemo.AppHost/Program.cs&lt;/code&gt;:
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp" data-line-numbers="true"&gt;var builder = DistributedApplication.CreateBuilder(args);

--&amp;gt; var sql = builder.AddSqlServer(&amp;quot;sql&amp;quot;)
--&amp;gt;    .WithLifetime(ContainerLifetime.Persistent);

--&amp;gt; var db = sql.AddDatabase(&amp;quot;XafAspireDemoDb&amp;quot;);

builder
    .AddProject&amp;lt;Projects.XafAspireDemo_Blazor_Server&amp;gt;(&amp;quot;xafaspiredemo-blazor-server&amp;quot;)
    .WithHttpsEndpoint()
--&amp;gt;    .WithReference(db)
--&amp;gt;    .WaitFor(db);

builder.Build().Run();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  First, the call to &lt;code&gt;AddSqlServer&lt;/code&gt; establishes the
  component of the orchestration for your application system. The
  call &lt;code&gt;WithLifetime(ContainerLifetime.Persistent)&lt;/code&gt; is
  often useful in development, because the container would
  otherwise be started and stopped with each run of the
  application system, which results in loss of any test data.
  With the &lt;code&gt;Persistent&lt;/code&gt; parameter, the container is
  left running when the rest of the application system stops,
  which speeds up the next run and retains data.
&lt;/p&gt;
&lt;p&gt;
  The database reference for a demo database is passed through to
  the Blazor Server project, and the &lt;code&gt;WaitFor&lt;/code&gt; call
  makes sure that the database is ready for action before the
  Blazor Server app attempts to access it.
&lt;/p&gt;
&lt;p&gt;
  That’s all it is on the orchestration side! It’s interesting
  that this approach to working with SQL Server does not need you
  to understand anything about connection strings and other
  specific details, for the first time in SQL Server history!
&lt;/p&gt;
&lt;p&gt;
  Nevertheless, of course we need to find out how the Blazor
  Server app connects to the new dependency now. Aspire has some
  automatic handling that finds out how the container with SQL
  Server can be contacted, and it provides a connection string
  automatically in an environment variable. The name of that
  variable is constructed similar to those environment variables
  that overload configuration file content, and it incorporates
  the name of the database in the setup. For the code above, the
  environment variable name is
  &lt;code&gt;ConnectionStrings__XafAspireDemoDb&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;
  By running the application at the current point, keeping in
  mind that the connection to the new containerized database is
  not being used yet, you can see that a SQL Server container is
  started (for example in Docker Desktop), and that the dashboard
  displays the new dependency correctly. The environment variable
  with the connection string is also visible in the dashboard.
&lt;/p&gt;
&lt;p&gt;
  &lt;img alt="" src="https://community.devexpress.com/blogs/news/20250404-xaf-aspire-2/2025-04-04-001838@2x.png" style="width:718px;"&gt;
&lt;/p&gt;
&lt;p&gt;
  &lt;img alt="" src="https://community.devexpress.com/blogs/news/20250404-xaf-aspire-2/2025-04-04-001839@2x.png" style="width:704px;"&gt;
&lt;/p&gt;
&lt;p&gt;
  The connection string includes a local port number, which is
  served by a proxy service provided by Aspire. The password for
  the database user &lt;code&gt;sa&lt;/code&gt; is auto-generated by the
  Aspire adapter.
&lt;/p&gt;
&lt;p&gt;
  &lt;img alt="" src="https://community.devexpress.com/blogs/news/20250404-xaf-aspire-2/2025-04-04-001840@2x.png" style="width:660px;"&gt;
&lt;/p&gt;
&lt;p&gt;
  One change is now missing to allow the Blazor Server app to use
  the containerized SQL Server. Edit the file
  &lt;code&gt;XafAspireDemo.Blazor.Server/Startup.cs&lt;/code&gt; and find
  the block in the &lt;code&gt;ConfigureServices&lt;/code&gt; method where
  the &lt;code&gt;connectionString&lt;/code&gt; is assigned. In the default
  XAF template, the code loads the connection string by calling
  &lt;code&gt;Configuration.GetConnectionString&lt;/code&gt;. Replace this
  code with a simple evaluation of the environment variable:
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp" data-line-numbers="true"&gt;    //options.UseInMemoryDatabase(&amp;quot;InMemory&amp;quot;);

    // The environment variable is published by the Aspire Host
--&amp;gt;    string connectionString = 
--&amp;gt;        Environment.GetEnvironmentVariable(&amp;quot;ConnectionStrings__XafAspireDemoDb&amp;quot;);

#if EASYTEST
    if (
        Configuration.GetConnectionString(&amp;quot;EasyTestConnectionString&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  Now you can run the application again, and the SQL Server in
  the container will be used instead of any other instance you
  used before.
&lt;/p&gt;
&lt;h3 id="a-little-bit-more"&gt;A little bit more…&lt;/h3&gt;
&lt;p&gt;
  One of the great details about setting your project up to use
  infrastructure containers is that other devs can easily execute
  the project on their machines without having to prepare their
  environment. For example, I was able to run the complete demo
  solution on my Mac at this point! There are two details I’d
  like to bring up in this regard.
&lt;/p&gt;
&lt;p&gt;
  First, I simply used
  &lt;code&gt;dotnet run --project XafAspireDemo.AppHost&lt;/code&gt; on the
  Mac, and there was a surprisingly large number of warnings and
  errors as soon as I tried to do anything in the dashboard. It
  turned out that this happened because I had not explicitly
  trusted the dev-time HTTPS certificates generated by .NET. This
  is usually not a big deal in my experience, it just leads to
  the occasional warning, but the Aspire Dashboard seems to rely
  on these certificates to a much greater extent for its gRPC
  connections.
&lt;/p&gt;
&lt;p&gt;
  You can read all about using HTTPS with ASP.NET Core
  &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-9.0&amp;amp;tabs=visual-studio%2Clinux-sles#trust-the-aspnet-core-https-development-certificate" target="_blank" rel="nofollow noreferrer"&gt;in this Microsoft documentation&lt;/a&gt;, and the simple command
  &lt;code&gt;dotnet dev-certs https --trust&lt;/code&gt; establishes the
  necessary trust and the gRPC connection issues go away.
&lt;/p&gt;
&lt;p&gt;
  Second, when running without a debugger attached, the standard
  behavior of XAF changes with regard to automatic database
  schema updates and updater execution. In a production
  deployment, you would deal with this as described in
  &lt;a href="https://docs.devexpress.com/eXpressAppFramework/113239/deployment/production-database-and-application-updates" target="_blank" rel="nofollow noreferrer"&gt;the XAF documentation here&lt;/a&gt;, but for my dev purposes I decided to extend the automatic
  update mechanism to cover the Aspire scenario I was using.
&lt;/p&gt;
&lt;p&gt;
  I edited the file
  &lt;code&gt;XafAspireDemo.Blazor.Server/BlazorApplication.cs&lt;/code&gt;,
  which includes a line where the environment is checked for an
  attached debugger - if this is found, an automatic update is
  executed. I extended this line to accept an environment
  variable as an alternative:
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp" data-line-numbers="true"&gt;--&amp;gt; if(Environment.GetEnvironmentVariable(&amp;quot;ASPIRE_DEBUG&amp;quot;) != null || System.Diagnostics.Debugger.IsAttached) {
    e.Updater.Update();
    e.Handled = true;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  Now I modified the Aspire host startup logic in
  &lt;code&gt;XafAspireDemo.AppHost/Program.cs&lt;/code&gt; to set this
  variable on startup:
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp" data-line-numbers="true"&gt;builder
    .AddProject&amp;lt;Projects.XafAspireDemo_Blazor_Server&amp;gt;(&amp;quot;xafaspiredemo-blazor-server&amp;quot;)
--&amp;gt;    .WithEnvironment(&amp;quot;ASPIRE_DEBUG&amp;quot;, &amp;quot;true&amp;quot;)
    .WithHttpsEndpoint()
    .WithReference(db)
    .WaitFor(db);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  With these changes in place, the demo solution now runs
  perfectly on my Mac!
&lt;/p&gt;
&lt;h2 id="an-additional-service"&gt;Orchestrate Additional Application Services&lt;/h2&gt;
&lt;p&gt;
  So far, the orchestration has two parts: the SQL Server and the
  Blazor Server app. I’ll add an extra service to the application
  system now, which will be called from the test controller in
  the Blazor app.
&lt;/p&gt;
&lt;p&gt;
  I start by creating a new project and adding it to the
  solution. Then I add a reference to the project
  &lt;code&gt;XafAspireDemo.ServiceDefaults&lt;/code&gt; to the new project,
  and a reference to the new project to the project
  &lt;code&gt;XafAspireDemo.AppHost&lt;/code&gt;.
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash" data-line-numbers="true"&gt;&amp;gt; dotnet new webapi -n XAFAspireDemo.DemoService

&amp;gt; dotnet sln add XAFAspireDemo.DemoService/XAFAspireService.DemoService.csproj

&amp;gt; dotnet add XAFAspireDemo.DemoService/XAFAspireService.DemoService.csproj reference XafAspireDemo.ServiceDefaults/XafAspireDemo.ServiceDefaults.csproj

&amp;gt; dotnet add XafAspireDemo.AppHost reference XAFAspireDemo.DemoService/XAFAspireService.DemoService.csproj
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  I add a class &lt;code&gt;Telemetry&lt;/code&gt; to the new service
  project, similar to the one in the Blazor Server project, but
  using its own identifiers and names.
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp" data-line-numbers="true"&gt;using System.Diagnostics;
using System.Diagnostics.Metrics;

namespace XafAspireDemo.DemoService
{
    public class Telemetry : IDisposable
    {
        public ActivitySource ActivitySource { get; }
        public Meter Meter { get; }
        public string MeterName =&amp;gt; Meter.Name;
        public Counter&amp;lt;long&amp;gt; ImportantBusinessValueRetrievalCounter { get; }
        public Histogram&amp;lt;double&amp;gt; ImportantBusinessValueRetrievalDuration { get; }

        public Telemetry(string serviceName = &amp;quot;XafAspireDemo.DemoService&amp;quot;, string version = &amp;quot;1.0.0&amp;quot;)
        {
            ActivitySource = new ActivitySource(serviceName, version);
            Meter = new Meter(serviceName, version);

            ImportantBusinessValueRetrievalCounter = Meter.CreateCounter&amp;lt;long&amp;gt;(
                &amp;quot;important_business_value.retrieval_count&amp;quot;
            );
            ImportantBusinessValueRetrievalDuration = Meter.CreateHistogram&amp;lt;double&amp;gt;(
                &amp;quot;important_business_value.retrieval_duration&amp;quot;
            );
        }

        public void Dispose()
        {
            ActivitySource.Dispose();
            Meter.Dispose();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  I replace the template code in
  &lt;code&gt;XAFAspireDemo.DemoService/Program.cs&lt;/code&gt; with this:
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp" data-line-numbers="true"&gt;using XafAspireDemo.DemoService;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddOpenApi();

builder.Services.AddAspireServiceDefaults();
builder.Services.ConfigureOpenTelemetry(builder.Configuration, builder.Environment);

var telemetry = new Telemetry();
builder.Services.AddSingleton(telemetry);

builder
    .Services.AddOpenTelemetry()
    .WithTracing(tracing =&amp;gt; tracing.AddSource(&amp;quot;XafAspireDemo.DemoService&amp;quot;))
    .WithMetrics(metrics =&amp;gt;
    {
        metrics.AddMeter(telemetry.MeterName);
    });

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseHttpsRedirection();

app.MapGet(
        &amp;quot;/important-business-value&amp;quot;,
        (Telemetry telemetry) =&amp;gt;
        {
            using var activity = telemetry.ActivitySource.StartActivity(
                &amp;quot;ImportantBusinessValueRetrieval&amp;quot;
            );

            var importantBusinessValue = Random.Shared.Next(1, 10000);

            telemetry.ImportantBusinessValueRetrievalCounter.Add(1);

            if (activity != null)
            {
                activity.Stop();
                var durationMs = activity.Duration.TotalMilliseconds;
                telemetry.ImportantBusinessValueRetrievalDuration.Record(durationMs);
            }

            return Results.Ok(new { ImportantBusinessValue = importantBusinessValue });
        }
    )
    .WithName(&amp;quot;GetImportantBusinessValue&amp;quot;)
    .WithOpenApi();

app.MapDefaultAspireDevEndpoints();

app.Run();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  This is all familiar code by now, just a few details to point
  out:
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    The helpers &lt;code&gt;AddAspireServiceDefaults&lt;/code&gt;,
    &lt;code&gt;ConfigureOpenTelemetry&lt;/code&gt; and
    &lt;code&gt;MapDefaultAspireDevEndpoints&lt;/code&gt; are shared with the
    Blazor Server project for consistency
  &lt;/li&gt;
  &lt;li&gt;
    The startup pattern is very similar to that used in the
    Blazor Server app as well
  &lt;/li&gt;
  &lt;li&gt;
    The implementation of the handler for the
    &lt;code&gt;/important-business-value&lt;/code&gt; endpoint uses the same
    patterns for the activity and the meters as the code in the
    sample controller of the Blazor app.
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  Now I modify the file
  &lt;code&gt;XafAspireDemo.AppHost/Program.cs&lt;/code&gt; to add the new
  project to the orchestration. Note that I change the existing
  call to &lt;code&gt;WithHttpsEndpoint&lt;/code&gt; to pass an explicit name
  - Aspire doesn’t like more than one parameterless call because
  it doesn’t assign auto-generated names.
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp" data-line-numbers="true"&gt;...
var db = sql.AddDatabase(&amp;quot;XafAspireDemoDb&amp;quot;);

--&amp;gt; var demoService = builder
--&amp;gt;     .AddProject&amp;lt;Projects.XAFAspireDemo_DemoService&amp;gt;(&amp;quot;demoservice&amp;quot;)
--&amp;gt;     .WithHttpsEndpoint(name: &amp;quot;demoservice-https&amp;quot;);

builder
    .AddProject&amp;lt;Projects.XafAspireDemo_Blazor_Server&amp;gt;(&amp;quot;xafaspiredemo-blazor-server&amp;quot;)
    .WithEnvironment(&amp;quot;ASPIRE_DEBUG&amp;quot;, &amp;quot;true&amp;quot;)
--&amp;gt;   .WithHttpsEndpoint(name: &amp;quot;xafaspiredemo-blazor-server-https&amp;quot;)
    .WithReference(db)
--&amp;gt;   .WithReference(demoService)
    .WaitFor(db);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  To call the new service from the test controller, I need to
  make an HTTP client available to it. I modify
  &lt;code&gt;XafAspireDemo.Blazor.Server/Startup.cs&lt;/code&gt; and add
  this line:
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp" data-line-numbers="true"&gt;...
services.ConfigureOpenTelemetry(Configuration, WebHostEnvironment);

--&amp;gt; services.AddHttpClient();

services.ConfigureOpenTelemetryTracerProvider(builder =&amp;gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  Now I can use the HTTP client to call the service from the
  controller in
  &lt;code&gt;XafAspireDemo.Blazor.Server/Controllers/ImportantBusinessOperationsController.cs&lt;/code&gt;.
&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp" data-line-numbers="true"&gt;...
	{
	    Thread.Sleep(new Random().Next(500, 5000));
	});
	
--&amp;gt; 	var httpClientFactory = serviceProvider.GetRequiredService&amp;lt;IHttpClientFactory&amp;gt;();
--&amp;gt; 	var httpClient = httpClientFactory.CreateClient();
--&amp;gt; 	var response = await httpClient.GetFromJsonAsync&amp;lt;ImportantBusinessValueResponse&amp;gt;(
--&amp;gt; 	    &amp;quot;https://demoservice/important-business-value&amp;quot;
--&amp;gt; 	);
--&amp;gt; 	logger.LogInformation(
--&amp;gt; 	    &amp;quot;Received important business value from service: {ImportantBusinessValue}&amp;quot;,
--&amp;gt; 	    response?.ImportantBusinessValue
--&amp;gt; 	);
}
catch (Exception ex)
{
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  An interesting detail: the URL for the service request uses the
  hostname &lt;code&gt;demoservice&lt;/code&gt;. This is possible because the
  host configures the service as a dependency. As a consequence,
  DNS resolution for the Blazor Server allows access to this name
  and resolves it to the target service.
&lt;/p&gt;
&lt;p&gt;
  That completes the changes! When I run the application now, the
  Aspire Dashboard shows the new structure. The log output
  includes items from the new service now, the metrics are
  included (select the correct resource to see them!), and since
  the service endpoint reports its own activities, you also see
  nested activities in the Traces page now.
&lt;/p&gt;
&lt;p&gt;
  &lt;img alt="" src="https://community.devexpress.com/blogs/news/20250404-xaf-aspire-2/2025-04-04-001841@2x.png" style="width:712px;"&gt;
&lt;/p&gt;
&lt;p&gt;
  &lt;img alt="" src="https://community.devexpress.com/blogs/news/20250404-xaf-aspire-2/2025-04-04-001842@2x.png" style="width:627px;"&gt;
&lt;/p&gt;
&lt;h2&gt;Your Feedback Matters!&lt;/h2&gt;
&lt;p&gt;
  In the final upcoming part of this small series, I will go into
  some deployment scenarios &lt;a href="https://github.com/oliversturm/XafAspireDemo/tree/demo-step-2" target="_blank" style="background-color:#ffff99;"&gt;for this GitHub sample&lt;/a&gt;. As always, p&lt;span&gt;lease send your feedback about Aspire, our plans or your existing and future uses of Aspire&amp;nbsp;&amp;nbsp;— thanks to all of you who have already done that! — and any questions or ideas, we will attempt to consider everything!&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-survey-id="40077d12-325d-4826-b368-352ebb6c0003" data-survey-auth-required="false"&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 21 Apr 2025 20:28:00 Z</pubDate>
      <dc:creator>Oliver Sturm (DevExpress)</dc:creator>
    </item>
  </channel>
</rss>