Settings Results in 4 milliseconds

[hot reload not working] hot reload only works whe ...
Category: .Net 7

Question hot reload only works with assets in Visual Studio 2019, when I modify ...


Views: 0 Likes: 37
Asp.Net Core GRPC Client Error: the type name "Gre ...
Category: .Net 7

Question How do you resolve the error "the type name "GreeterClient" does not exist in the type ...


Views: 1098 Likes: 91
The FAST and the Fluent: A Blazor story
The FAST and the Fluent A Blazor story

The FAST and the Fluent A Blazor story is a detailed introduction to the Fluent UI Blazor library, which is built on top of Web Components and modern web standards. The library was created by Microsoft's UX engineers and designers with the goal of making it easier to create web components using standard web technologies.Web Components is an umbrella term that refers to a collection of web standards aimed at creating custom HTML elements. These standards include the ability to define new HTML tags, plug into a standard component lifecycle, encapsulate HTML rendering, CSS encapsulation and parameterization. The Fluent UI Blazor library uses these W3C Web Component standards, making it possible for components built with FAST to function in the same way as built-in, normal HTML elements.The Fluent design system is another key component of the Fluent UI Blazor library. It was originally developed by Microsoft for its Metro design system and contains guidelines for the designs and interactions used within software. The latest version of the Fluent design system, Fluent 2, was released in 2021.Blazor is a framework for building interactive web applications with .NET. Developers build interactive UIs using C# instead of JavaScript. Code can be executed both client-side and server-side and, via MAUI, even run natively on iOS, Android, and Tizen devices. The Fluent UI Blazor library is built on top of Blazor, making it possible to use the Fluent design system with this framework.The Fluent UI Blazor library was initially developed by Microsoft's FAST team as a wrapper for each Fluent UI Web Component. This meant that a Blazor component was created that rendered a web component, using the same names, parameters and enumerations as the web component but in Razor syntax and with the C# language. The first version of the library was released around the end of 2021 and contained about 40 different components.The Fluent UI Blazor library has been successful since its release, with almost 1.1 million NuGet package downloads as of writing this article. It is not an official part of ASP.NET Core, which means it's not officially supported and isn't committed to ship updates as part of any official .NET updates. However, Microsoft itself believes in its future and is using the library in a couple of projects already.The Fluent UI Blazor library has continued to evolve and expand since its initial release. The latest version, version 4, was released in November 2021 and includes almost 70 components. These are not only just wrappers of the Fluent UI Web Components anymore, but also pure Blazor components that leverage the Fluent Design System for their user interface, others make it easier to work with Fluent design in your application. The library is now independent from the FAST team and a bit closer to the Blazor team.In conclusion, the Fluent UI Blazor library is a powerful tool for building interactive web applications using .NET and the Fluent design system. It offers a wide range of components that can be used in any modern browser and is built on top of Web Components and modern web standards. The library has been successful since its release and continues to evolve and expand, with new versions being released regularly.


MSBUILD : error MSB1011: Specify which project or ...
Category: Other

Question How do you resolve the error "MSBUILD error MSB1011 Specify which project or solutio ...


Views: 0 Likes: 8
Micro-service application running inside Docker Co ...
Category: Docker

Problem <s ...


Views: 137 Likes: 71
[HTTP Error 500.30]: Failed to load coreclr.Except ...
Category: Servers

Question How do you solve for error that says "HTTP Error 500.30-ASP.NET Core a ...


Views: 0 Likes: 37
Announcing .NET Chiseled Containers
Announcing .NET Chiseled Containers

.NET chiseled Ubuntu container images are now GA and can be used in production, for .NET 6, 7, and 8. Canonical also announced the general availability of chiseled Ubuntu containers. Chiseled images are the result of a long-term partnership and design collaboration between Canonical and Microsoft. We announced chiseled containers just over a year ago, as a new direction. They are now ready for you to use in your production environment and to take advantage of the value they offer. The images are available in our container repos with the following tag 8.0-jammy-chiseled. .NET 6 and 7 variants differ only by version number. These images rely on Ubuntu 22.04 (Jammy Jellyfish), as referenced by jammy in the tag name. We made a few videos on this topic over the last year, which provide a great overview Chiselled Ubuntu Containers .NET Containers advancements in .NET 8 | .NET Conf 2023 .NET in Ubuntu and Chiseled Containers We also published a container workshop for .NET Conf that uses chiseled containers for many of its examples. The workshop also uses OCI publish, which pairs well with chiseled containers. Chiseled images General-purpose container images are not the future of cloud apps The premise of chiseled containers is that container images are the best deployment vehicle for cloud apps, but that typical images contain far too many components. Instead, we need to slice away all but the essential components. Chiseled container images do that. That helps — a lot — with size and security. The number one complaint category we hear about container images is around CVE management. It’s hard to do well. We’ve built automation that rebuilds .NET images within hours of Alpine, Debian, and Ubuntu base image updates on Docker Hub. That means the images we ship are always fresh. However, most users don’t have that automation, and end up with stale images in their registries that fail CVE scans, often asking why our images are stale (when they are not). We know because they send us their image scan reports. There has to be a better way. It’s really easy to demo the difference, using anchore/syft (using Docker). Those commands show us the number of “Linux components” in three images we publish, for Debian, Ubuntu, and Alpine, respectively. $ docker run --rm anchore/syft mcr.microsoft.com/dotnet/runtime8.0 | grep deb | wc -l 92 $ docker run --rm anchore/syft mcr.microsoft.com/dotnet/runtime8.0-jammy | grep deb | wc -l 105 $ docker run --rm anchore/syft mcr.microsoft.com/dotnet/runtime8.0-alpine | grep apk | wc -l 17 One can guess that it’s pretty easy for a CVE to apply to one of these images, given the number of components. In fact, .NET doesn’t use most of those components! Alpine shines here. Here’s the result for the same image, but chiseled. $ docker run --rm anchore/syft mcr.microsoft.com/dotnet/runtime8.0-jammy-chiseled | grep deb | wc -l 7 That gets us down to 7 components. In fact, the list is so short, we can just look at all of them. $ docker run --rm anchore/syft mcr.microsoft.com/dotnet/runtime8.0-jammy-chiseled | grep deb base-files 12ubuntu4.4 deb ca-certificates 20230311ubuntu0.22.04.1 deb libc6 2.35-0ubuntu3.4 deb libgcc-s1 12.3.0-1ubuntu1~22.04 deb libssl3 3.0.2-0ubuntu1.12 deb libstdc++6 12.3.0-1ubuntu1~22.04 deb zlib1g 11.2.11.dfsg-2ubuntu9.2 deb That’s a very limited set of quite common dependencies. For example, .NET uses OpenSSL, for everything crypto, including TLS connections. Some customers need FIPS compliance and are able to enable that since .NET relies on OpenSSL. Native AOT apps are similar, but need one less component. We care so much about limiting size and component count that we created an image just for it, removing libstdc++6. This image is new and still in preview. $ docker run --rm anchore/syft mcr.microsoft.com/dotnet/nightly/runtime-deps8.0-jammy-chiseled-aot | grep deb | wc -l 6 As expected, that image only contains 6 components. Chiseled images are also much smaller. We can see that, this time with (uncompressed) aspnet images. $ docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep mcr.microsoft.com/dotnet/aspnet mcr.microsoft.com/dotnet/aspnet 8.0-jammy-chiseled 110MB mcr.microsoft.com/dotnet/aspnet 8.0-alpine 112MB mcr.microsoft.com/dotnet/aspnet 8.0-jammy 216MB mcr.microsoft.com/dotnet/aspnet 8.0 217MB In summary, Chiseled images Slice a little over 100MB (uncompressed) relative to existing Ubuntu images. Match the size of Alpine, the existing fan favorite for size. Are the smallest images we publish with glibc compatibility Contain the fewest components, reducing CVE exposure. Are a great choice for matching dev and prod, given the popularity of Ubuntu for dev machines. Have the strongest support offering of any image variant we publish. Distroless form factor We’ve been publishing container images for nearly a decade. Throughout that time, we’ve heard regular requests to make images smaller, to remove components, and to improve security. Even as we’ve improved .NET container images, we’ve continued to hear those requests. The fundamental problem is that we cannot change the base images we pull from Docker Hub (beyond adding to them). We needed something revolutionary to change this dynamic. Many users have pointed us to Google Distroless over the years. “Distroless” images contain only your application and its runtime dependencies. They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution. That’s a great description, taken from the distroless repo. Google deconstructs various Linux distros, and builds them back as atoms, but only using the most necessary atoms to run apps. That’s brilliant. We have a strong philosophy of only taking artifacts from and aligning with the policies of upstream distros, specifically Alpine, Debian, and Ubuntu. That way, we have the same relationship with the upstream provider (like Ubuntu) as the user. If there is an issue (outside of .NET), we’re looking for resolution from the same singular party. That’s why we never adopted Google Distroless and have been waiting for something like Ubuntu chiseled, from the upstream provider. Ubuntu chiseled is a great expression of the distroless form factor. It delivers on the same goals as the original Google project, but comes from the distro itself. You might worry that this is all new and untested and that something is going to break. In fact, we’ve been delivering distroless images within Microsoft for a few years. At Microsoft, we use Mariner Linux. A few years ago, we asked the Mariner team to create a distroless solution for our shared users. Microsoft teams have been hosting apps in production using .NET + Mariner distroless images since then. That has worked out quite well. Security posture The two most critical components missing from these images are a shell and a package manager. Their absence really limits what an attacker can do. curl and wget are also missing from these images. One of the first things an attacker typically does is download a shell script (from a server they control) and then runs it. Yes, that really happens. That’s effectively impossible with these images. The required components to enable that are just not there and not acquirable. We also ship these images as non-root. $ docker inspect mcr.microsoft.com/dotnet/aspnet8.0-jammy-chiseled | grep User "User" "", "User" "1654", All new files and directories are created with a UID and GID of 0 — Dockerfile reference This change further constrains the type of operations that are allowed in these images. On one hand, a non-root user isn’t able to run apt install commands, but since apt isn’t even present, that doesn’t matter. More practically, the non-root user isn’t able to update app files. The app files will be copied into the container as root, making it impossible for the non-root user to alter them or to add files to the same directory. The non-root user only has read and execute permissions for the app. You might wonder why it took us so long to support these images after announcing them over a year ago. That’s a related and ironic story. Many image scanners rely on scanning the package manager database, but since the package manager was removed, the required database was removed too. Ooops! Instead, our friends at Canonical had to synthesize a package manager database file through other means, as opposed to bringing part of the package manager back just to enable scanning. In the end, we have an excellent solution that optimizes for security and for scanning, without needing to compromise either. All of the anchore/syft commands shown earlier in the post are evidence that the scanning solution works. App size There are multiple ways to control the size of container images. The following slide from our .NET Conf presentation demonstrates that with a sample app. There are two primary axis Base image, for framework-dependent apps. Publish option, for self-contained apps. On the left, the chiseled variants of aspnet result in significant size wins. The smaller chiseled image — “composite” — derives its additional reductions by building parts of the .NET runtime libraries in a more optimized way. That will be covered in more detail in a follow-up post. On the right, self-contained + trimming drops the image size a lot more, since all the unused .NET libraries are removed. Native AOT drops the image size to below 10MB. That’s a welcome and shocking surprise. Note that native AOT only works for console apps and services, not for web sites. That may change in a later release. You might be wondering how to select between these choices. Framework dependent deployment has the benefit of maximum layer sharing. That means sharing copies of .NET in your registry and within a single machine (if you host multiple .NET apps together). Build times are also shorter. Self-contained apps win on size and registry pull, but have more limited sharing (only runtime-deps is shared). Adoption Chiseled images are the biggest change to our container image portfolio since we added support for Alpine, several years ago. We recommend that users take a deeper look at this change. Note The chiseled images we publish don’t include ICU or tzdata, just like Alpine (except for “extra” images). Please comment on dotnet-docker #5014 if you need these libraries. Users adopting .NET 8 are the most obvious candidates for chiseled containers. You will already be making changes, so why not make one more change? In many cases, you’ll just be using a different image tag, with significant new benefits. Ubuntu and Debian users can achieve very significant size savings over the general-purpose images you’ve had available until now. We recommend that you give chiseled images serious considerations. Alpine users have always been very well served and that isn’t changing. We’ve also included a non-root user in .NET 8 Alpine images. We’d recommend that Alpine users first switch to non-root hosting and then consider the additional benefits of chiseled images. We expect that many Alpine users will remain happy with Alpine and others will prefer Ubuntu Chiseled now that it also has a small variant. It’s great to have options! We’ve often been asked if we’d ever switch our convenient version tags — like 8.0 — to Alpine or (now) Chiseled. Such a change would break many apps, so we commit to publishing Debian images for those tags, effectively forever. It’s straightforward for users to opt-in to one of our other image types. We believe equally in compatibility and choice, and we’re offering both. Summary We’ve been strong advocates of Ubuntu chiseled containers from the moment we saw the first demo. That demo has now graduated all the way to a GA release, with Canonical and Microsoft announcing availability together. This level of collaboration will continue as we support these new images and work together on what’s next. We’re looking forward to feedback, since there are likely interesting scenarios we haven’t yet considered. We’ve had the benefit of working closing with Canonical on this project and making these images available to .NET users first. However, we’re so enthusiastic about this project, we want all developers to have the opportunity to use chiseled images. We encourage other developer ecosystems to stongly consider offering chiseled images, like Java, Python, and Node.js. We’ve had recent requests for information on chiseled images, after the .NET Conf presentations. Perhaps a year from now, chiseled images will have become a common choice for many developers. Over time, we’ve seen the increasing customer challenge of operationally managing containers, largely related to CVE burden. We believe that chiseled images are a great solution for helping teams reduce cost and deploy apps with greater confidence. The post Announcing .NET Chiseled Containers appeared first on .NET Blog.


Upgrading to .Net Core 3.1 Error Visual Studio 201 ...
Category: .Net 7

Problem When upgrading to Dot Net Core 3.1 from .Net Core 3.0 ...


Views: 671 Likes: 106
Dotnet 8 Error: exec /usr/bin/dotnet: no such fil ...
Category: Questions

Question Why is this error happening?Dotnet 8 Error &nbsp;exec /usr/bin/dotnet no ...


Views: 0 Likes: 8
could not load System.ComponentModel.AsyncComplete ...
Category: .Net 7

Question How do you resolve "could not load System.ComponentModel.Async ...


Views: 399 Likes: 85
Selecting the Best DTP Software for Your Needs
Selecting the Best DTP Software for Your Needs

DTP application is a program employed by graphic designers, copy writers, editors and illustrators to develop books and eBooks, mags, newspapers, custom business cards, stationery, annual reports, greeting cards, labels, article content, blogs, social websites posts, notifications, brochures, pamphlets, posters, flyers, menus, and interactive PDFs. These applications typically include a variety of design capabilities just like drawing equipment, image treatment functions like cropping and resizing photographs, layout grids for organising content on a page plus the ability to export into multiple formats which includes PDF, EPS, JPEG, PSD, PNG, JPEG, GIF and HTML. DTP software may additionally include features like fine-tuned typography options such as kerning, traffic monitoring and leading, special text effects, a built-in word processor, photography adjustment alternatives, optical perimeter angle and support for crawls and dining tables of subject matter. When choosing a desktop writing software, first of all to consider is the kind of projects you want to produce. While most programs can be used to design digital and print out documents, some are better suited to specific types of tasks. For example , a few programs are certainly more suited for creating newsletters while others are designed to produce complex styles for pamphlets and flyers. In addition , you should look at your budget and level of encounter when deciding on a DTP program. Some applications are free to use while others demand a subscription fee. To help you select the right dtp program for your needs, the www.ticketsbrooklyn.net/what-is-a-data-room Data Quadrant Buyer’s Guide offers compiled a directory of the top applications in the market. Each has been examined by actual users, carefully verified and visualized in an easy-to-understand chart.


raspberry Pi: systemd[1]: Condition check resulted ...
Category: Linux

Question How to do you resolve systemd[1] Condition check resulted in Bluetoot ...


Views: 1557 Likes: 107
Asp.Net Core Error: InvalidOperationException: The ...
Category: .Net 7

Problem&nbsp;<span style="background-color #fff ...


Views: 341 Likes: 96
How to use a Text File as a Template to Send Email ...
Category: .Net 7

AnswerOne way to accomplish this is by creating a text file and defining your template ...


Views: 385 Likes: 104
 The .NET Stacks #62: ?? And we&#x27;re back
The .NET Stacks #62 ?? And we&#x27;re back

This is the web version of my weekly newsletter, The .NET Stacks, originally sent to email subscribers on September 13, 2021. Subscribe at the bottom of the post to get this right away!Happy Monday! Miss me? A few of you said you have, but I'm 60% sure that's sarcasm.As you know, I took the last month or so off from the newsletter to focus on other things. I know I wasn't exactly specific on why, and appreciate some of you reaching out. I wasn't comfortable sharing it at the time, but I needed to take time away to focus on determining the next step in my career. If you've interviewed lately, I'm sure you understand ... it really is a full-time job.  I'm happy to say I've accepted a remote tech lead role for a SaaS company here. I'm rested and ready, so let's get into it! I'm trying something a little different this week—feel free to let me know what you think.?? My favorite from last weekASP.NET 6.0 Minimal APIs, why should you care?Ben FosterWe've talked about Minimal APIs a lot in this newsletter and it's quite the hot topic in the .NET community. An alternative way to write APIs in .NET 6 and beyond, there's a lot of folks wondering if it's suitable for production, or can lead to misuse. Ben notes "Minimal simply means that it contains the minimum set of components needed to build HTTP APIs ... It doesn’t mean that the application you build will be simple or not require good design.""I find that one of the biggest advantages to Minimal APIs is that they make it easier to build APIs in an opinionated way. After many years building HTTP services, I have a preferred approach. With MVC I would replace the built-in validation with Fluent Validation and my controllers were little more than a dispatch call to Mediatr. With Minimal APIs I get even more control. Of course if MVC offers everything you need, then use that."In a similar vein, Nick Chapsas has a great walkthrough on strategies for building production-ready Minimal APIs. No one expects your API to be in one file, and he shows practical ways to deal with dependencies while leveraging minimal API patterns. Damian Edwards has a nice Twitter thread, as well. As great as these community discussions are, I really think the greatest benefit is getting lost the performance gains.?? Community and eventsIncreasing developer happiness with GitHub code scanningSam PartingtonIf you work in GitHub, you probably already know that GitHub utilizes code scanning to find security vulnerabilities and errors in your repository. Sam Partington writes about something you might not know they use CodeQL—their internal code analysis engine—to protect themselves from common coding mistakes. Here's what Sam says about loopy performance issues "In addition to protecting against missing error checking, we also want to keep our database-querying code performant. N+1 queries are a common performance issue. This is where some expensive operation is performed once for every member of a set, so the code will get slower as the number of items increases. Database calls in a loop are often the culprit here; typically, you’ll get better performance from a batch query outside of the loop instead.""We created a custom CodeQL query ... We filter that list of calls down to those that happen within a loop and fail CI if any are encountered. What’s nice about CodeQL is that we’re not limited to database calls directly within the body of a loop?calls within functions called directly or indirectly from the loop are caught too."You can check out the post for more details and learn how to use these queries or make your own.More from last weekSimon Bisson writes about how to use the VS Code editor in your own projects.The Netflix Tech Blog starts a series on practical API design and also starts writing about their decision-making process.The .NET Docs Show talks about micr0 frontends with Blazor.For community standups, Entity Framework talks about OSS projects, ASP.NET has an anniversary, .NET MAUI discusses accessibility, and Machine Learning holds office hours.?? Web developmentHow To Map A Route in an ASP.NET Core MVC applicationKhalid AbuhakmehIf you're new to ASP.NET Core web development, Khalid put together a nice post on how to add an existing endpoint to an existing ASP.NET Core MVC app. Even if you aren't a beginner, you might learn how to resolve sticky routing issues. At the bottom of the post, he has a nice checklist you should consider when adding a new endpoint.More from last weekBen Foster explores custom model binding with Minimal APIs in .NET 6.Thomas Ardal debugs System.FormatException when launching ASP.NET Core.Jeremy Morgan builds a small web API with Azure Functions and SQLite.Ed Charbeneau works with low-code data grids and Blazor.Scott Hanselman works with a Minimal API todo app.?? The .NET platformUsing Source Generators with Blazor components in .NET 6Andrew LockWhen Andrew was upgrading a Blazor app to .NET 6, he found that source generators that worked in .NET 5 failed to discover Blazor components in his .NET 6 app because of changes to the Razor compilation process.He writes "The problem is that my source generators were relying on the output of the Razor compiler in .NET 5 ... My source generator was looking for components in the compilation that are decorated with [RouteAttribute]. With .NET 6, the Razor tooling is a source generator, so there is no 'first step'; the Razor tooling executes at the same time as my source generator. That is great for performance, but it means the files my source generator was relying on (the generated component classes) don't exist when my generator runs."While this is by design, Andrew has a great post underlying the issue and potential workarounds.More from last weekMark Downie writes about his favorite improvements in .NET 6.Sergey Vasiliev writes about optimizing .NET apps.Pawel Szydziak writes cleaner, safer code with SonarQube, Docker, and .NET Core.Sam Basu writes about how to develop for desktop in 2022, and also about developing for .NET MAUI on macOS.Paul Michaels manually parses a JSON string using System.Text.Json.Johnson Towoju writes logs to SQL Server using NLog.Andrew Lock uses source generators with Blazor components in .NET 6.Rick Strahl launches Visual Studio Code cleanly from a .NET app.Jirí Cincura calls a C# static constructor multiple times.? The cloudMinimal Api in .NET 6 Out Of Process Azure FunctionsAdam StorrWith all this talk about Minimal APIs, Adam asks can I use it with the new out-of-process Azure Functions model in .NET 6?He says "Azure Functions with HttpTriggers are similar to ASP.NET Core controller actions in that they handle http requests, have routing, can handle model binding, dependency injection etc. so how could a 'Minimal API' using Azure Functions look?"More from last weekDamien Bowden uses Azure security groups in ASP.NET Core with an Azure B2C identity provider.Jon Gallant works with the ChainedTokenCredential in the Azure Identity library.Adam Storr uses .NET 6 Minimal APIs with out-of-process Azure Functions.?? ToolsNew Improved Attach to Process Dialog ExperienceHarshada HoleWith the 2022 update, Visual Studio is improving the debugging experience—included is a new Attach to Process dialog experience.Harshada says "We have added command-line details, app pool details, parent/child process tree view, and the select running window from the desktop option in the attach to process dialog. These make it convenient to find the right process you need to attach. Also, the Attach to Process dialog is now asynchronous, making it interactive even when the process list is updating." The post walks through these updates in detail.More from last weekJeremy Likness looks at the EF Core Azure Cosmos DB provider.Harshada Hole writes about the new Attach to Process dialog experience in Visual Studio.Ben De St Paer-Gotch goes behind the scenes on Docker Desktop.Esteban Solano Granados plays with .NET 6, C# 10, and Docker.?? Design, testing, and best practicesShip / Show / Ask A modern branching strategyRouan WilsenachRouan says "Ship/Show/Ask is a branching strategy that combines the features of Pull Requests with the ability to keep shipping changes. Changes are categorized as either Ship (merge into mainline without review), Show (open a pull request for review, but merge into mainline immediately), or Ask (open a pull request for discussion before merging)."More from last weekLiana Martirosyan writes about enabling team learning and boost performance.Sagar Nangare writes about measuring user experience in modern applications and infrastructure.Neal Ford and Mark Richards talk about the hard parts of software architecture.Derek Comartin discusses event-sourced aggregate design.Steve Smith refactors to value objects.Sam Milbrath writes about holding teams accountable without micromanaging.Helen Scott asks how can you stay ahead of the curve as a developer?Rouan Wilsenach writes about a ship / show / ask branching strategy.Jeremy Miller writes about integration Testing using the IHost Lifecycle with xUnit.Net.?? Podcasts and VideosServerless Chats discusses serverless for beginners.The .NET Core Show talks about DotPurple With Michael Babienco.The Changelog talks to a lawyer about GitHub Copilot.Technology and Friends talks to Sam Basu about .NET MAUI.Visual Studio Toolbox talks about Web Live Preview.The ASP.NET Monsters talk about new Git commands.Adventures in .NET talk about Jupyter notebooks.The On .NET Show migrates apps to modern authentication and processes payments with C# and Stripe.


Why is AspNet 6 Application always running in Prod ...
Category: .Net 7

Question I just upgraded Asp.Net 5 Application to Asp.Net 6, when I run the command&nbsp;< ...


Views: 0 Likes: 38
Tips and Trick Developing in C# and Dotnet 8
Category: Other

<div class="group w-full text-gray-800 darktext-gray-100 border-b border-black/10 darkborder-gray- ...


Views: 0 Likes: 8
Evaluating Data Rooms Online
Evaluating Data Rooms Online

Data rooms online are virtual places that allow secure peer to peer for a number of purposes. They could be used for M&A, capital increases, audits, ideal reviews and tenders, and are generally useful for any project which involves confidential facts. Some services offer a total lifecycle control system with built-in project operations features. Place simplify internal and external communications, reduces costs of techniques and improve outcomes. Several vendors also provide a mobile software and multi-lingual user interface just for data space users to work with files on the go from virtually any device. Additional common features include drag-and-drop and mass upload of any extendable, automated index numbering simple navigation, dynamic watermarking to limit excess duplication and distribution, and a clear and intuitive access hierarchy make. Other crucial features to consider happen to be single sign-on, customizable customer permissions and analytics, support pertaining to multiple ‘languages’, and local apps with regards to iOS and Android. Additionally it is crucial to locate a data room that provides complete security. Various vendors provide you with granular stats which could track activity within the data room that help with reliability protocols. Some even allow you to hook up non-disclosure agreements to specific documents or perhaps whole parts of the data place, which can be kept up to date automatically advantages of virtual data room and need viewer personal unsecured each time your data is seen. Pricing models are an crucial consideration the moment evaluating varied data bedroom providers. Several charge a per-page charge while others, such as FirmRoom, possess flat month to month fees meant for unlimited storage area and users. This allows package teams to pay attention to the most important aspects of the data area and not worry about document and user overages.


OSS Power-Ups: MassTransit – Webinar Recording
OSS Power-Ups MassTransit – Webinar Recording

The recording of our webinar, OSS Power-Ups MassTransit, with Chris Patterson, is available. This was the thirteenth episode of our OSS Power-Ups series, where we put a spotlight on open-source .NET projects. Subscribe to our community newsletter to receive notifications about future webinars. Join Chris Patterson, the author of MassTransit, for an insightful webinar as we delve into the messaging patterns supported by MassTransit. In today’s rapidly evolving tech landscape, efficient communication between software components is more crucial than ever. MassTransit, an open-source distributed application framework for .NET, provides tools and techniques to help you navigate the complexities of distributed systems. In this webinar, Chris Patterson will guide you through the complexities of messaging patterns, illustrating how MassTransit can streamline communication, enhance scalability, and boost resilience in your applications. Whether you’re a seasoned developer looking to refine your messaging skills or a newcomer eager to explore the world of distributed systems, this webinar will provide valuable insights and practical knowledge that will empower you to build more robust and efficient software solutions. Webinar agenda 0000 – Intro 0117 – About OSS PowerUps 0310 – Hello, Chris! 0625 – About Chris and MassTransit 0800 – When to use MassTransit 1142 – MassTransit in Action “DropBox” Pattern 1520 – Publishing a Message 1549 – Watching Messages in RabbitMQ 1706 – Consuming Messages 1920 – Configuring MassTransit 2125 – Message Idempotency and Deduplication 2450 – Q Who generates IDs? 2705 – Advantages of MassTransit over bare Message Queues 3039 – Q Can communicate synchronously between MassTransit and RabbitMQ? 3305 – Retry Patterns and Failure Handling 3830 – Logging in MassTransit 3922 – Request/Response vs. Publish 4134 – Telemetry in MassTransit 4314 – Configuring Retries I 4534 – Q Where are failing Messages going? 4709 – Configuring Retries II 4900 – Does MassTransit retry on RabbitMQ? 5128 – How to unlearn the Request/Response approach? 5504 – Evolving API Contracts in Responses (Avoiding Monoliths) 10038 – Q How does MassTransit compare to EasyNetQ and NServiceBus? 10235 – Q How to version Events? 10715 – Q Can I control the Message Serialization to the Queue? 10740 – Q Are Sagas always correlated by a GUID? 10834 – Q Are there Tutorials on Sagas? 11028 – Q Is that a Choreographer instead of an Orchestrator? 11150 – Q Can a Content-Type be used for Versioning? 11256 – Q What is GreenPipes? 11600 – Q How are Riders different from Transports? 11830 – Q Where can I see good examples of MassTransit’s State Machine? 11948 – Q Can you explain Lifts in the old State-Machine Implementation? 12026 – Q Is it worth using Real Broker Services for Integration Tests? 12318 – Q How to share Contracts between Projects? 12527 – Q Can you perform Request Validation? 12600 – Q Are Sagas conceptually compatible with Azure Service Bus Sessions? 12714 – Outro Resources MassTransit Website MassTransit GitHub Repository Sponsor Chris Demo Project About the presenter Chris Patterson Chris Patterson is an Enterprise Software Architect, the founder of Loosely Coupled, LLC, and the author of MassTransit, an open-source distributed application framework for building message-based applications. Before starting his own company, Chris spent 24 years leading the architecture and development of multiple platforms and services in a Fortune 10 company leveraging a broad range of technologies. Chris is a multi-year Microsoft MVP award recipient and regularly produces software development-related content on YouTube. Follow Chris on Twitter and LinkedIn.


Microsoft Machine Learning mlContext Forecasting d ...
Category: Machine Learning

Question Microsoft Machine Learning mlContext Forecasting does not have ForecastBySsa DotNet Cor ...


Views: 1122 Likes: 87
What is New in Asp Net 7 and EF Core 7 (Best Featu ...
Category: Research

Asp.Net Core 7Navigation If you want the Entity to be included in a ...


Views: 0 Likes: 19
Asp.Net 5 Development Notes (DotNet Core 3.1 Study ...
Category: Software Development

Study Notes to use when progra ...


Views: 423 Likes: 61
The type namespace QuickGrid could not be found
Category: .NET 5

Questin How do you resolve the error that says, The type namespace QuickGrid could not be found ...


Views: 0 Likes: 43
Machine Learning Best Resources
Category: Machine Learning

<span style="font-weight bold; font-size large; textline underli ...


Views: 325 Likes: 88
running dotnet in docker exec /usr/bin/dotnet: no ...
Category: .NET 5

Question Building and Running dotnet 8 in Docker Container throws an error" /usr/bin/dot ...


Views: 0 Likes: 17
Ubuntu Nginx Create Symbolic Links In Sites Enabl ...
Category: Linux

When working in Ubuntu Server to deploy an application, it is important to know how to create Symbol ...


Views: 585 Likes: 91
[SEO] Why Using Links Instead of Click Functions f ...
Category: Network

[SEO ] Why Using Links Instead of Click Functions is very important ...


Views: 337 Likes: 82
Entity Framework Core Error: To change the IDENTIT ...
Category: Entity Framework

Question How do you resolve the Entity ...


Views: 2404 Likes: 105
What is domain driven design in Asp.Net 8?
Category: Research

Domain-Driven Design (DDD) is an approach to software development that emphasizes the importance ...


Views: 0 Likes: 29
How to Bind a CheckBox data to a Model Integer Pro ...
Category: Databases

When working in ASP.Net Core 2.2 Razor Engine, you might find yourself wanting to bind data from ...


Views: 620 Likes: 79
How to Remove Duende IdentityServer from Blazor We ...
Category: .Net 7

Question How do you Remove Duende IdentityServer from Blazor Web Assembly Application in Visual ...


Views: 0 Likes: 39
Developing Optimized GitHub Actions with .NET and Native AOT
Developing Optimized GitHub Actions with .NET and ...

Developing GitHub Actions with .NET and Native AOT has become increasingly popular in recent years due to its numerous benefits. Here are some compelling reasons why you should consider using .NET for your next GitHub Action1. Cross-platform compatibility .NET is a cross-platform framework that can run on Windows, Linux, and macOS. This means that your GitHub Actions can be executed seamlessly across different operating systems, making it easier to deploy and manage your codebase.2. Performance optimization .NET uses just-in-time (JIT) compilation, which allows for faster execution of your code. Additionally, the use of native AOT (Ahead-of-Time) compilation can further optimize your code's performance, making it run even faster.3. Scalability .NET is designed to be highly scalable and can handle large amounts of data and traffic. This makes it an ideal choice for GitHub Actions that need to process large volumes of data or execute complex workflows.4. Integration with other Microsoft technologies .NET integrates seamlessly with other Microsoft technologies such as Azure DevOps, Visual Studio, and PowerShell. This means that you can leverage these tools to enhance your GitHub Actions development experience.5. Community support The .NET community is large and active, with many resources available for developers. This makes it easier to find help and support when needed, ensuring that your GitHub Actions are developed efficiently and effectively.Overall, developing GitHub Actions with .NET and Native AOT offers numerous benefits, including cross-platform compatibility, performance optimization, scalability, integration with other Microsoft technologies, and community support. By leveraging these benefits, you can create efficient and effective GitHub Actions that meet your specific needs.


The Recently Leaked Secret to Marijuana News Discovered
The Recently Leaked Secret to Marijuana News Disco ...

The Recently Leaked Secret to Marijuana News Discovered The Unexposed Secret of Marijuana News If you’re against using Cannabis as you do not need to smoke you’re misinformed. As there is barely any cannabis left in a roach, some people today argue that the song is all about running out of cannabis and not having the ability to acquire high, exactly like the roach isn’t able to walk because it’s missing a leg. If you’re thinking about consuming cannabis please consult your health care provider first. Before visiting the list, it’s important to be aware of the scientific reason cannabis works as a medication generally, and more specifically, the scientific reason it can send cancer into remission. At the moment, Medical Cannabis was still being used to take care of several health-related problems. In modern society, it is just starting to receive the recognition it deserves when it comes to treating diseases such as Epilepsy. In nearly all the nation, at the present time, marijuana is illegal. To comprehend what marijuana does to the brain first you’ve got to know the key chemicals in marijuana and the various strains. If you are a person who uses marijuana socially at the occasional party, then you likely do not have that much to be concerned about. If you’re a user of medicinal marijuana, your smartphone is possibly the very first place you start looking for your community dispensary or a health care provider. As an issue of fact, there are just a few types of marijuana that are psychoactive. Medical marijuana has entered the fast-lane and now in case you reside in Arizona you can purchase your weed without leaving your vehicle. Medical marijuana has numerous therapeutic effects which will need to be dealt with and not only the so-called addictive qualities. If you’re using marijuana for recreational purposes begin with a strain with a minimal dose of THC and see the way your body reacts. Marijuana is simpler to understand because it is both criminalized and decriminalized, based on the place you go in the nation. If a person is afflicted by chronic depression marijuana can directly affect the Amygdala that is accountable for your emotions. Things You Won’t Like About Marijuana News and Things You Will Much enjoy the wine industry was just two or three decades past, the cannabis business has an image problem that’s keeping people away. In the event you want to learn where you are able to find marijuana wholesale companies near you, the very best place to seek out such companies is our site, Weed Finder. With the cannabis industry test.com growing exponentially, and as more states start to legalize, individuals are beginning to learn that there is far more to cannabis than simply a plant that you smoke. In different states, the work of legal marijuana has produced a patchwork of banking and tax practices. Then the marijuana sector is ideal for you. Know what medical cannabis options can be found in your state and the way they respond to your qualifying medical condition. They can provide medicinal benefits, psychotropic benefits, and any combination of both, and being able to articulate what your daily responsibilities are may help you and your physician make informed, responsible decisions regarding the options that are appropriate for you, thus protecting your employment, your family and yourself from untoward events. In the modern society, using drugs has become so prevalent it has come to be a component of normal life, irrespective of age or gender. Using marijuana in the USA is growing at a quick rate.


How to Run DotNet Core 3.0 in Watch Mode without i ...
Category: .Net 7

Run DotNet Core 3.0 in Watch Mode without installing any&nbsp;extensions ...


Views: 673 Likes: 95
.NET MAUI Community Toolkit 2023 Highlights
.NET MAUI Community Toolkit 2023 Highlights

The .NET MAUI Community Toolkit is an open-source library that serves as a companion to .NET MAUI, offering developers a rich set of controls, converters, and helpers designed to accelerate app development on the .NET MAUI platform. With a focus on community-driven innovation, it has become an indispensable tool for developers looking to enhance their .NET MAUI applications.In 2023, the project evolved into a dynamic hub of activity, engaging over 40 contributors who have collectively pushed the project forward. The GitHub repository has been instrumental in shaping the toolkit into a more powerful and efficient resource for .NET MAUI developers.The year that was marked consistent progress, with nine significant releases launched, each adding more value and capabilities to the toolkit. There were 260 commits made during the year, which enhanced and expanded the toolkit's functionalities. Additionally, 521 files were changed to ensure the highest quality standards.The project has grown in influence, with over 4,190 repositories now depending on the CommunityToolkit.Maui. The number of downloads from NuGet signifies the widespread adoption and trust in the toolkit, with 679,767 downloads in 2023 alone.Apart from bug fixes, several new features were added during 2023, including the Media Element control, which allows developers to seamlessly play video and audio content within their .NET MAUI applications. The Windows Maps integration brings the power of .NET MAUI maps directly to the Windows platform, enhancing location-based services in apps. SpeechToText and Speech Recognition capabilities were also added, allowing users to interact and command their applications through spoken language.The FolderPicker and FileSaver take file management to the next level by allowing users to effortlessly navigate and select directories and save files with ease. Keyboard extensions were also introduced, giving developers greater control over the on-screen keyboard. The Badge API was added to display notification counts on app icons, keeping users engaged and informed.The .NET MAUI Community Toolkit extends beyond the primary NuGet package, with documentation housed in the Docs repository and the versatile .NET MAUI Markup package for developers inclined towards a non-XAML approach. Both these pillars of the toolkit have been receiving consistent updates, highlighted by the 192 commits made to the Docs repository and the 104 commits made to the .NET MAUI Markup repository.The project has achieved remarkable milestones, with over 1 million total downloads in 2023 alone, a testament to its reliability, robustness, and the trust it has garnered within the developer community. This feat accentuates the toolkit's role as an essential asset in the .NET MAUI ecosystem, continuously evolving to empower developers to build incredible cross-platform applications.The .NET MAUI Community Toolkit is a testament to the power of community-driven innovation and the importance of collaboration in software development. With a focus on continuous improvement and expansion, the project will continue to be an indispensable tool for developers looking to enhance their .NET MAUI applications.


Error: The type or namespace UI does not exist in ...
Category: .Net 7

Problem The type or namespace UI does not exist in the namespace Microsoft.AspNetCore.Identity b ...


Views: 1799 Likes: 98
HTTP Error 502.5 - Process Failure: The current .N ...
Category: Network

Problem The current .Net SDK does not support targeting .NET Core 3.0. Either target .NET Core 2 ...


Views: 845 Likes: 108
Improvements & Changes in Android resource generation in .NET 8
Improvements & Changes in Android resource generat ...

With the release of .NET 8 we are introducing a new system for generating the C# code used to access Android Resources. The system which generated a Resource.designer.cs file in Xamarin.Android, .NET 6 and .NET 7 has been deprecated. The new system generates a single _Microsoft.Android.Resource.Designer assembly.  This will contain all the final resource classes for every assembly. What are Android Resources? All Android applications will have some sort of user interface resources in them. They often have the user interface layouts in the form of XML file, images and icons in the form of png or svg files and values which contain things like styles and theming. See the Google’s documentation for an in-depth look at Android resources. Part of the android build process is to compile these resources into a binary form, this is done by the android sdk tool aapt2. To access these resources android exposed an API which allows you to pass an integer id to retrieve the resource. SetContentView (2131492864); As part of the aapt2 build process the file R.txt is generated which contains a mapping from the “string” name of the resource to the id. For example layout/Main.xml might map to the id 2131492864. To access this data from C# we need a way to expose this in code. This is handled by a Resource class in the projects $(RootNamespace). We take the values from the R.txt and expose them in this class. In the system that shipped with .NET 7 and prior releases, this class was written to the Resource.designer.cs file. And it allowed users to write maintainable code by not hard coding ids. So the call from above would actually look like this SetContentView (Resource.Layout.Main); The Resource.Id.Main would map to the Id which was produced by aapt2. Why make this new system? The old system had some issues which impact both app size and startup performance. In the old system every Android assembly had its own set of Resource classes in it. So we effectively had duplicate code everywhere. So if you used AndroidX in your project every assembly which referenced AndroidX would have a Resource designer Id class like this public class Resource { public class Id { // aapt resource value 0x7F0A0005 public const int seekBar = 2131361797; // aapt resource value 0x7F0A0006 public const int menu = 2131361798; } } This code would be duplicated in each library. There are may other classes such as Layout/Menu/Style, all of which have these duplicate code in them. Also each of these Resource classes needed to be updated at runtime to have the correct values. This is because it is only when we build the final app and generate the R.txt file do we know the ids for each of these resources. So the application Resource classes are the only ones with the correct ids. The old system used a method called UpdateIdValues which was called on startup. This method would go through ALL the library projects and update the resource ids to match the ones in the application. Depending on the size of the application this can cause significant delays to startup. Here is an example of the code in this method public static void UpdateIdValues() { globalLibrary.Resource.Id.seekBar = globalFoo.Foo.Resource.Id.seekBar; globalLibrary.Resource.Id.menu = globalFoo.Foo.Resource.Id.menu; } Even worse because of the UpdateIdValues code the trimmer could not remove any of these classes. So even if the application only used one or two fields , all of them are preserved.  The new system reworks all of this to make it trimmer-friendly, almost ALL of the code shown above will no longer be produced. There is no need to even have an UpdateIdValues call at all. This will improve both app size and startup time.  How it works .NET 8 Android will have the MSBuild property $(AndroidUseDesignerAssembly) set to true by default. This will turn off the old system completely. Manually changing this property to false will re-enable the old system. The new system relies on parsing the R.txt file which aapt2 generates as part of the build process. Just before the call to run the C# compiler, the R.txt file will be parsed and generate a new assembly. The assembly will be saved in the the IntermediateOutputPath. It will also be automatically added to the list of References for the app or library.  For library projects we generate a reference assembly rather than a full assembly. This signals to the compiler that this assembly will be replaced at runtime. (A reference assembly is an assembly which contains an assembly-level ReferenceAssemblyAttribute.) For application projects we generate a full assembly as part of the UpdateAndroidResources target. This ensures that we are using the final values from the R.txt file. It is this final assembly which will be deployed with the final package. In addition to the assembly a source file will be generated. This will be __Microsoft.Android.Resource.Designer.cs, or __Microsoft.Android.Resource.Designer.fs if you use F# . This contains a class which will derive from the Resource class. It will exist in the projects’ $(RootNamespace). This is the glue which allows existing code to work. Because the namespace of the Resource class will not change. For application projects the Resource class in the project RootNamespace will be derived from the ResourceConstants class in the designer assembly. This is to maintain backward compatibility with the way the older Resource.designer.cs files worked for application projects. Tests show we can get about 8% improvement in startup time. And about a 2%-4% decrease in overall package size. Will my NuGet packages still work? Some of you might be worried that with this change your existing package references will stop working. Do not worry, the new system has introduced a Trimmer step which will upgrade assembly references which use the old system to use the new one. This will be done automatically as part of the build. This trimmer step analyses the IL in all the assemblies looking for places where the old Resource.designer fields were used. It will then update those to use the new Designer assembly properties. It will also completely remove the old Resource.designer in that assembly. So even if you use old packages you should still see the benefit of this new system. The Linker step should cover almost all of the code where the Resource.designer.cs fields are accessed. However if you come across a problem please open an issue at https//github.com/xamarin/xamarin-android/issues/new/choose. This will apply to any android assembly reference which is pre net8.0-android. Packages built with the new system cannot be used with previous versions of .NET Android. Please consider using multi targeting if you need to support .NET 7 or Classic Xamarin.Android. NuGet Package Authors Do you maintain a NuGet package which contains Android Resources? If so you will need to make some changes. Firstly there is no need to ship the new _Microsoft.Android.Resource.Designer.dll with your NuGet. It will be generated at build time by the application consuming the NuGet. The new system is incompatible with the Classic Pre .NET Xamarin.Android and .NET 6/7 Android Packages. So if you want to continue to support Classic Xamarin.Android as well as .NET 8 you will need to multitarget your assemblies. If you no longer need to support Class Xamarin.Android you can upgrade your project to the .NET Sdk Style project and use the following <TargetFrameworks>net7.0-android;net8.0-android</TargetFrameworks> Classic Xamarin.Android is going out of Support next year so this is probably the best option. If you need to support both systems, you can use Xamarin.Legacy.Sdk to both for both Xamarin.Android and net8.0-android. Xamarin.Legacy.Sdk is un-supported, so it will only be useful as a stop gap measure while your users upgrade to .NET 8. See the Xamarin.Legacy.Sdk GitHub site https//github.com/xamarin/Xamarin.Legacy.Sdk for details on how to use this package. Since .NET 6 android the AndroidResource, AndroidAsset, AndroidEnvironment, AndroidJavaLibrary, EmbeddedNativeLibrary and AndroidNativeLibrary items are no longer packaged inside the assembly. There is an .aar file generated at build time which contains this data and will be named the same as the assembly. For things to work correctly this .aar file will need to be shipped in the NuGet along side the assembly. If the .aar is not included it will result in missing resource errors at runtime, such as System.MissingMethodException 'Method not found int .Style.get_MyTheme()' The .aar will be included by default if you use dotnet pack on your project and specify your NuGet properties and settings in the csproj. However if you are using a .nuspec you will need to manually add the .aar file to your list of files to be included. The changes related to .aar files and embedded files are documented in OneDotNetEmbeddedResources.md Summary So the new system should result in slightly smaller package sizes, and fast start up times. The impact will be greater the more resources you are using in your app. The post Improvements & Changes in Android resource generation in .NET 8 appeared first on .NET Blog.


Building 3D Applications and Content with .NET MAUI and Evergine
Building 3D Applications and Content with .NET MAU ...

This is a guest blog post by Jorge Canton from Plain Concepts. Jorge co-founded the technology start-up Syderis and dedicated over 12 years to specializing in computer graphics, game engines, and graphics tools. Currently, he holds the position of Research Director at Plain Concepts, where he is actively involved in the development of Evergine, a cutting-edge 3D graphics engine tailored for industry applications. Have you ever used an e-commerce platform and wished you could visualize products from any angle using a 3D representation instead of static images? Have you ever looked at a map of a large shopping mall and thought it would be much easier to navigate if you could explore a 3D map? In this article, we will learn how to achieve all of this and more using .NET .NET MAUI. What is Evergine? Evergine is a cross-platform 3D engine developed in C# back in 2012. Evergine is renowned for its seamless integration capabilities, making it a top choice for industrial projects. It can easily be incorporated into existing projects or paired with other technologies. With Evergine, you can craft applications compatible with a wide range of platforms, including Windows, Linux, Android, iOS, Hololens, Meta Quest/Quest2/Quest Pro, Pico, and Web. Evergine also boasts seamless integration with various UI technologies, including WPF, Forms, SDL, UWP, Html/Javascript, WinUI, and now, even .NET MAUI. We are committed to staying up to date with the latest .NET versions and tooling to provide our customers with the best possible experience. The key features of Evergine include Advanced PBR rendering Bring your application to a new level of realism using Physically based rendering and materials. Component based graphics engine Evergine is a Component based Engine. This allows us to reduce the complexibility and overall development cost of your applications. Customizable RenderPipeline and RenderPath Customize the way that Evergine render your applications to adapt to new scenarios. Physics Engine simulations Simulate a wide range of physics behaviors, collisions, and joints, both in 3D and 2D. Advanced Post-Processing pipeline Increase the realism of your application using post-Proccessing effects like Tone Mapping, SSR, SSAO, TAA, and much more! Photometric Lighting and Cameras Use real lightning units and setup your virtual camera using advanced exposure parameters. Modern graphics API support Increase the performance of your applications thanks to next generation graphics APIs DirectX12, Vulkan and Metal. Apart from this, Evergine supports DirectX11, OpenGL (ES) and WebGL. Modern GPU Particles 3D and 2D particles can be used to enhance the visuals of your app, creating a wide range of effects. Advanced Animation System The animation system extracts the object, skeleton and morphing animations of your 3d models, easing the blending between them. Lot of options are offered, like synchronized blending and multiple tracks at the same time. Evergine is entirely free to use, with no licensing fees or royalties, making it suitable for both commercial and non-commercial projects. Evergine’s business model revolves around providing additional services such as Priority Support We provide assistance and technical support for any questions or problems you may have using Evergine on your projects with a 72h SLA. Source Code Access We grant you total access to the source code of Evergine. Professional Services You will have access to training sessions, one-to-one sessions, proof of concepts and new features according to your needs. Prices are available on the official web site How Evergine works with .NET .NET MAUI In the latest Evergine release, a new .NET MAUI project template has been introduced. With this template, Evergine enables you to create a standard .NET MAUI project that incorporates an EvergineView control, which can be seamlessly integrated into any view of your application. This EvergineView serves as a canvas for a 3D scene generated by Evergine, allowing you to configure it using Evergine Studio. The EvergineView is an abstract custom .NET MAUI control that enables you to work seamlessly across Windows, Android, and iOS platforms. public class EvergineView View { public static readonly BindableProperty ApplicationProperty = BindableProperty.Create(nameof(Application), typeof(EvergineApplication), typeof(EvergineView), null); public static readonly BindableProperty DisplayNameProperty = BindableProperty.Create(nameof(DisplayName), typeof(string), typeof(EvergineView), string.Empty); public EvergineApplication Application { get { return (EvergineApplication)this.GetValue(ApplicationProperty); } set { this.SetValue(ApplicationProperty, value); } } public string DisplayName { get { return (string)this.GetValue(DisplayNameProperty); } set { this.SetValue(DisplayNameProperty, value); } } public event EventHandler PointerPressed; public event EventHandler PointerMoved; public event EventHandler PointerReleased; internal void StartInteraction() => this.PointerPressed?.Invoke(this, EventArgs.Empty); internal void MovedInteraction() => this.PointerMoved?.Invoke(this, EventArgs.Empty); internal void EndInteraction() => this.PointerReleased?.Invoke(this, EventArgs.Empty); } On the flip side, the rendering implementation was created using a custom handler for each platform. The following code serves as an example of the Android handler. public partial class EvergineViewHandler ViewHandler<EvergineView, AndroidSurfaceView> { private AndroidSurface androidSurface; private AndroidWindowsSystem windowsSystem; public EvergineViewHandler(IPropertyMapper mapper, CommandMapper commandMapper = null) base(mapper, commandMapper) { } public static void MapApplication(EvergineViewHandler handler, EvergineView evergineView) { handler.UpdateApplication(evergineView, evergineView.DisplayName); } internal void UpdateApplication(EvergineView view, string displayName) { if (view.Application is null) { return; } // Register Windows system view.Application.Container.RegisterInstance(this.windowsSystem); // Creates XAudio device var xaudio = new globalEvergine.OpenAL.ALAudioDevice(); view.Application.Container.RegisterInstance(xaudio); System.Diagnostics.Stopwatch clockTimer = System.Diagnostics.Stopwatch.StartNew(); this.windowsSystem.Run( () => { this.ConfigureGraphicsContext(view.Application as SneakerApp.MyApplication, this.androidSurface); view.Application.Initialize(); }, () => { var gameTime = clockTimer.Elapsed; clockTimer.Restart(); view.Application.UpdateFrame(gameTime); view.Application.DrawFrame(gameTime); }); } protected override AndroidSurfaceView CreatePlatformView() { this.windowsSystem = new AndroidWindowsSystem(this.Context); this.androidSurface = this.windowsSystem.CreateSurface(0, 0) as AndroidSurface; return this.androidSurface.NativeSurface; } private void ConfigureGraphicsContext(MyApplication application, Surface surface) { var graphicsContext = new VKGraphicsContext(); graphicsContext.CreateDevice(); SwapChainDescription swapChainDescription = new SwapChainDescription() { SurfaceInfo = surface.SurfaceInfo, Width = surface.Width, Height = surface.Height, ColorTargetFormat = PixelFormat.R8G8B8A8_UNorm, ColorTargetFlags = TextureFlags.RenderTarget | TextureFlags.ShaderResource, DepthStencilTargetFormat = PixelFormat.D24_UNorm_S8_UInt, DepthStencilTargetFlags = TextureFlags.DepthStencil, SampleCount = TextureSampleCount.None, IsWindowed = true, RefreshRate = 60, }; var swapChain = graphicsContext.CreateSwapChain(swapChainDescription); swapChain.VerticalSync = true; var graphicsPresenter = application.Container.Resolve<GraphicsPresenter>(); var firstDisplay = new globalEvergine.Framework.Graphics.Display(surface, swapChain); graphicsPresenter.AddDisplay("DefaultDisplay", firstDisplay); application.Container.RegisterInstance(graphicsContext); surface.OnScreenSizeChanged += (_, args) => { swapChain.ResizeSwapChain(args.Height, args.Width); }; } } In addition, the registration of the Evergine custom handler is performed in the MauiProgram.cs file of your project. public static class .NET MAUIProgram { public static .NET MAUIApp CreateMauiApp() { var builder = .NET MAUIApp.CreateBuilder(); builder .UseMauiApp<App>() .UseMauiEvergine() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); #if DEBUG builder.Logging.AddDebug(); #endif return builder.Build(); } } Finally, a 3D scene can be quite intricate and may comprise various assets, such as textures, materials, and models, etc. Evergine conveniently packages and transfers all 3D scene assets as raw assets to the device. To accomplish this, the Evergine template incorporates specific targets that label the 3D content as MauiAsset and injects it into the .NET MAUI target pipeline. Getting Started After downloading and installing Evergine from the official website, the Evergine launcher is the first thing you’ll encounter. It enables you to manage different versions, create new projects using various project templates, access sample projects, and find links to support and documentation. To initiate a new project from the Evergine launcher, navigate to the My Projects section and click on the Add New Project button The project configuration window will open, allowing you to select the Project Name, the disk location for your project, and the desired Evergine version to use. Additionally, you have the option to choose the new .NET MAUI template. After clicking the Create button, Evergine Studio will open. You can then add any primitive object to the scene and attach a Spinner component with values {x1, y2, z3} to enable rotation of the primitive. To access the .NET MAUI solution, simply open it from the File menu in Evergine Studio. When you launch the .NET MAUI solution in Visual Studio, you’ll discover two integrated projects within the solution. The first project is your Evergine project that you share between all templates, and the second is the .NET MAUI project, which references the Evergine project. Inside the .NET MAUI project, you’ll find the Platform folder, which houses platform-specific resources like the Android Manifest and Info.plist files. Within the Evergine folder, you’ll come across the EvergineView control. This control can be effortlessly integrated into your XAML pages, enabling you to include an Evergine canvas for rendering your 3D scenes. To deploy your project on various platforms, utilize the Run/Deploy button in Visual Studio. Please note that for iOS deployment, you’ll need to establish a connection between Visual Studio and a Mac, and have an iOS device (iPad or iPhone) linked to your Mac. Once you’ve successfully deployed your project within your .NET MAUI solution, you’ll attain results akin to the example depicted above. This showcases a fundamental XAML page in .NET MAUI, incorporating a Label and an EvergineView. While this serves as an example, you have the creative freedom to craft exceptional projects leveraging the latest .NET technologies and Evergine. You can explore our showcase app, which demonstrates how to seamlessly blend mobile app UI with 3D content and effectively communicate between Evergine and .NET MAUI UI. EverSneaks showcase app Repository https//github.com/EvergineTeam/EverSneaks CarRental showcase app (by @Javier Suarez) Repository https//github.com/jsuarezruiz/netmaui-carrental-app-challenge Evergine main resources In the official Evergine website you can find a lot of interesting resources to getting started with Evergine, the following are the most important. Evergine documentation Samples repository Video tutorials Youtube channel Feedback Contact Future The current .NET MAUI template use .NET 7 stable version. After the .NET 8 stable version is released in November, we will update the .NET MAUI template to .NET 8 stable version to be available use the latest improvement and features. We have full confidence that the community can craft exceptionally attractive applications by harnessing the power of these technologies. We’re excited to see what you can create by combining 3D with .NET MAUI!. We eagerly await your feedback. Happy coding with Evergine and .NET MAUI! The post Building 3D Applications and Content with .NET MAUI and Evergine appeared first on .NET Blog.


What’s new with identity in .NET 8
What’s new with identity in .NET 8

In April 2023, I wrote about the commitment by the ASP.NET Core team to improve authentication, authorization, and identity management in .NET 8. The plan we presented included three key deliverables New APIs to simplify login and identity management for client apps like Single Page Apps (SPA) and Blazor WebAssembly. Enablement of token-based authentication and authorization in ASP.NET Core Identity for clients that can’t use cookies. Improvements to documentation. All three deliverables will ship with .NET 8. In addition, we were able to add a new identity UI for Blazor web apps that works with both of the new rendering modes, server and WebAssembly. Let’s look at a few scenarios that are enabled by the new changes in .NET 8. In this blog post we’ll cover Securing a simple web API backend Using the new Blazor identity UI Adding an external login like Google or Facebook Securing Blazor WebAssembly apps using built-in features and components Using tokens for clients that can’t use cookies Let’s look at the simplest scenario for using the new identity features. Basic Web API backend An easy way to use the new authorization is to enable it in a basic Web API app. The same app may also be used as the backend for Blazor WebAssembly, Angular, React, and other Single Page Web apps (SPA). Assuming you’re starting with an ASP.NET Core Web API project in .NET 8 that includes OpenAPI, you can add authentication with a few steps. Identity is “opt-in,” so there are a few packages to add Microsoft.AspNetCore.Identity.EntityFrameworkCore – the package that enables EF Core integration A package for the database you wish to use, such as Microsoft.EntityFrameworkCore.SqlServer (we’ll use the in-memory database for this example) You can add these packages using the NuGet package manager or the command line. For example, to add the packages using the command line, navigate to the project folder and run the following dotnet commands dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore dotnet add package Microsoft.EntityFrameworkCore.InMemory Identity allows you to customize both the user information and the user database in case you have requirements beyond what is provided in the .NET Core framework. For our basic example, we’ll just use the default user information and database. To do that, we’ll add a new class to the project called MyUser that inherits from IdentityUser class MyUser IdentityUser {} Add a new class called AppDbContext that inherits from IdentityDbContext<MyUser> class AppDbContext(DbContextOptions<AppDbContext> options) IdentityDbContext<MyUser>(options) { } Providing the special constructor makes it possible to configure the database for different environments. To set up identity for an app, open the Program.cs file. Configure identity to use cookie-based authentication and to enable authorization checks by adding the following code after the call to WebApplication.CreateBuilder(args) builder.Services.AddAuthentication(IdentityConstants.ApplicationScheme) .AddIdentityCookies(); builder.Services.AddAuthorizationBuilder(); Configure the EF Core database. Here we’ll use the in-memory database and name it “AppDb.” It’s usedhere for the demo so it is easy to restart the application and test the flow to register and login (each run will start with a fresh database). Changing to SQLite will save users between sessions but requires the database to be properly created through migrations as shown in this EF Core getting started tutorial. You can use other relational providers such as SQL Server for your production code. builder.Services.AddDbContext<AppDbContext>( options => options.UseInMemoryDatabase("AppDb")); Configure identity to use the EF Core database and expose the identity endpoints builder.Services.AddIdentityCore<MyUser>() .AddEntityFrameworkStores<AppDbContext>() .AddApiEndpoints(); Map the routes for the identity endpoints. This code should be placed after the call to builder.Build() app.MapIdentityApi<MyUser>(); The app is now ready for authentication and authorization! To secure an endpoint, use the .RequireAuthentication() extension method where you define the auth route. If you are using a controller-based solution, you can add the [Authorize] attribute to the controller or action. To test the app, run it and navigate to the Swagger UI. Expand the secured endpoint, select try it out, and select execute. The endpoint is reported as 404 - not found, which is arguably more secure than reporting a 401 - not authorized because it doesn’t reveal that the endpoint exists. Now expand /register and fill in your credentials. If you enter an invalid email address or a bad password, the result includes the validation errors. The errors in this example are returned in the ProblemDetails format so your client can easily parse them and display validation errors as needed. I’ll show an example of that in the standalone Blazor WebAssembly app. A successful registration results in a 200 - OK response. You can now expand /login and enter the same credentials. Note, there are additional parameters that aren’t needed for this example and can be deleted. Be sure to set useCookies to true. A successful login results in a 200 - OK response with a cookie in the response header. Now you can rerun the secured endpoint and it should return a valid result. This is because cookie-based authentication is securely built-in to your browser and “just works.” You’ve just secured your first endpoint with identity! Some web clients may not include cookies in the header by default. If you are using a tool for testing APIs, you may need to enable cookies in the settings. The JavaScript fetch API does not include cookies by default. You can enable them by setting credentials to the value include in the options. Similarly, an HttpClient running in a Blazor WebAssembly app needs the HttpRequestMessage to include credentials, like the following request.SetBrowserRequestCredential(BrowserRequestCredentials.Include); Next, let’s jump into a Blazor web app. The Blazor identity UI A stretch goal of our team that we were able to achieve was to implement the identity UI, which includes options to register, log in, and configure multi-factor authentication, in Blazor. The UI is built into the template when you select the “Individual accounts” option for authentication. Unlike the previous version of the identity UI, which was hidden unless you wanted to customize it, the template generates all of the source code so you can modify it as needed. The new version is built with Razor components and works with both server-side and WebAssembly Blazor apps. The new Blazor web model allows you to configure whether the UI is rendered server-side or from a client running in WebAssembly. When you choose the WebAssembly mode, the server will still handle all authentication and authorization requests. It will also generate the code for a custom implementation of AuthenticationStateProvider that tracks the authentication state. The provider uses the PersistentComponentState class to pre-render the authentication state and persist it to the page. The PersistentAuthenticationStateProvider in the client WebAssembly app uses the component to synchronize the authentication state between the server and browser. The state provider might also be named PersistingRevalidatingAuthenticationStateProvider when running with auto interactivity or IdentityRevalidatingAuthenticationStateProvider for server interactivity. Although the examples in this blog post are focused on a simple username and password login scenario, ASP.NET Identity has support for email-based interactions like account confirmation and password recovery. It is also possible to configure multifactor authentication. The components for all of these features are included in the UI. Add an external login A common question we are asked is how to integrate external logins through social websites with ASP.NET Core Identity. Starting from the Blazor web app default project, you can add an external login with a few steps. First, you’ll need to register your app with the social website. For example, to add a Twitter login, go to the Twitter developer portal and create a new app. You’ll need to provide some basic information to obtain your client credentials. After creating your app, navigate to the app settings and click “edit” on authentication. Specify “native app” for the application type for the flow to work correctly and turn on “request email from users.” You’ll need to provide a callback URL. For this example, we’ll use https//localhost5001/signin-twitter which is the default callback URL for the Blazor web app template. You can change this to match your app’s URL (i.e. replace 5001 with your own port). Also note the API key and secret. Next, add the appropriate authentication package to your app. There is a community-maintained list of OAuth 2.0 social authentication providers for ASP.NET Core with many options to choose from. You can mix multiple external logins as needed. For Twitter, I’ll add the AspNet.Security.OAuth.Twitter package. From a command prompt in the root directory of the server project, run this command to store your API Key (client ID) and secret. dotnet user-secrets set "TwitterApiKey" "<your-api-key>" dotnet user-secrets set "TWitterApiSecret" "<your-api-secret>" Finally, configure the login in Program.cs by replacing this code builder.Services.AddAuthentication(IdentityConstants.ApplicationScheme) .AddIdentityCookies(); with this code builder.Services.AddAuthentication(IdentityConstants.ApplicationScheme) .AddTwitter(opt => { opt.ClientId = builder.Configuration["TwitterApiKey"]!; opt.ClientSecret = builder.Configuration["TwitterApiSecret"]!; }) .AddIdentityCookies(); Cookies are the preferred and most secure approach for implementing ASP.NET Core Identity. Tokens are supported if needed and require the IdentityConstants.BearerScheme to be configured. The tokens are proprietary and the token-based flow is intended for simple scenarios so it does not implement the OAuth 2.0 or OIDC standards. What’s next? Believe it or not, you’re done. This time when you run the app, the login page will automatically detect the external login and provide a button to use it. When you log in and authorize the app, you will be redirected back and authenticated. Securing Blazor WebAssembly apps A major motivation for adding the new identity APIs was to make it easier for developers to secure their browser-based apps including Single Page Apps (SPA) and Blazor WebAssembly. It doesn’t matter if you use the built-in identity provider, a custom login or a cloud-based service like Microsoft Entra, the end result is an identity that is either authenticated with claims and roles, or not authenticated. In Blazor, you can secure a razor component by adding the [Authorize] attribute to the component or to the page that hosts the component. You can also secure a route by adding the .RequireAuthorization() extension method to the route definition. The full source code for this example is available in the Blazor samples repo. The AuthorizeView tag provides a simple way to handle content the user has access to. The authentication state can be accessed via the context property. Consider the following <p>Welcome to my page!</p> <AuthorizeView> <Authorizing> <div class="alert alert-info">We're checking your credentials...</div> </Authorizing> <Authorized> <div class="alert alert-success">You are authenticated @context.User.Identity?.Name</div> </Authorized> <NotAuthorized> <div class="alert alert-warning">You are not authenticated!</div> </NotAuthorized> </AuthorizeView> The greeting will be shown to everyone. In the case of Blazor WebAssembly, when the client might need to authenticate asynchronously over API calls, the Authorizing content will be shown while the authentication state is queried and resolved. Then, based on whether or not you’ve authenticated, you’ll either see your name or a message that you’re not authenticated. How exactly does the client know if you’re authenticated? That’s where the AuthenticationStateProvider comes in. The App.razor page is wrapped in a CascadingAuthenticationState provider. This provider is responsible for tracking the authentication state and making it available to the rest of the app. The AuthenticationStateProvider is injected into the provider and used to track the state. The AuthenticationStateProvider is also injected into the AuthorizeView component. When the authentication state changes, the provider notifies the AuthorizeView component and the content is updated accordingly. First, we want to make sure that API calls are persisting credentials accordingly. To do that, I created a handler named CookieHandler. public class CookieHandler DelegatingHandler { protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include); return base.SendAsync(request, cancellationToken); } } In Program.cs I added the handler to the HttpClient and used the client factory to configure a special client for authentication purposes. builder.Services.AddTransient<CookieHandler>(); builder.Services.AddHttpClient( "Auth", opt => opt.BaseAddress = new Uri(builder.Configuration["AuthUrl"]!)) .AddHttpMessageHandler<CookieHandler>(); Note the authentication components are opt-in and available via the Microsoft.AspNetCore.Components.WebAssembly.Authentication package. The client factory and extension methods come from Microsoft.Extensions.Http. The AuthUrl is the URL of the ASP.NET Core server that exposes the identity APIs. Next, I created a CookieAuthenticationStateProvider that inherits from AuthenticationStateProvider and overrides the GetAuthenticationStateAsync method. The main logic looks like this var unauthenticated = new ClaimsPrincipal(new ClaimsIdentity()); var userResponse = await _httpClient.GetAsync("manage/info"); if (userResponse.IsSuccessStatusCode) { var userJson = await userResponse.Content.ReadAsStringAsync(); var userInfo = JsonSerializer.Deserialize<UserInfo>(userJson, jsonSerializerOptions); if (userInfo != null) { var claims = new List<Claim> { new(ClaimTypes.Name, userInfo.Email), new(ClaimTypes.Email, userInfo.Email) }; var id = new ClaimsIdentity(claims, nameof(CookieAuthenticationStateProvider)); user = new ClaimsPrincipal(id); } } return new AuthenticationState(user); The user info endpoint is secure, so if the user is not authenticated the request will fail and the method will return an unauthenticated state. Otherwise, it builds the appropriate identity and claims and returns the authenticated state. How does the app know when the state has changed? Here is what a login looks like from Blazor WebAssembly using the identity API async Task<AuthenticationState> LoginAndGetAuthenticationState() { var result = await _httpClient.PostAsJsonAsync( "login?useCookies=true", new { email, password }); return await GetAuthenticationStateAsync(); } NotifyAuthenticationStateChanged(LoginAndGetAuthenticationState()); When the login is successful, the NotifyAuthenticationStateChanged method on the base AuthenticationStateProvider class is called to notify the provider that the state has changed. It is passed the result of the request for a new authentication state so that it can verify the cookie is present. The provider will then update the AuthorizeView component and the user will see the authenticated content. Tokens In the rare event your client doesn’t support cookies, the login API provides a parameter to request tokens. An custom token (one that is proprietary to the ASP.NET Core identity platform) is issued that can be used to authenticate subsequent requests. The token is passed in the Authorization header as a bearer token. A refresh token is also provided. This allows your application to request a new token when the old one expires without forcing the user to log in again. The tokens are not standard JSON Web Tokens (JWT). The decision behind this was intentional, as the built-in identity is meant primarily for simple scenarios. The token option is not intended to be a fully-featured identity service provider or token server, but instead an alternative to the cookie option for clients that can’t use cookies. Not sure whether you need a token server or not? Read a document to help you choose the right ASP.NET Core identity solution. Looking for a more advanced identity solution? Read our list of identity management solutions for ASP.NET Core. Docs and samples The third deliverable is documentation and samples. We have already introduced new documentation and will be adding new articles and samples as we approach the release of .NET 8. Follow Issue #29452 – documentation and samples for identity in .NET 8 to track the progress. Please use the issue to communicate additional documentation or samples you are looking for. You can also link to the specific issues for various documents and provide your feedback there. Conclusion The new identity features in .NET 8 make it easier than ever to secure your applications. If your requirements are simple, you can now add authentication and authorization to your app with a few lines of code. The new APIs make it possible to secure your Web API endpoints with cookie-based authentication and authorization. There is also a token-based option for clients that can’t use cookies. Learn more about the new identity features in the ASP.NET Core documentation. The post What’s new with identity in .NET 8 appeared first on .NET Blog.


Microsoft.AspNetCore.Antiforgery.AntiforgeryValida ...
Category: .Net 7

Question How do you resolve the error in .Net 5 Login <span style="background- ...


Views: 507 Likes: 67
How to Create Symbolic links between two folders o ...
Category: Windows

Use CMD not Powershell &nbsp; mklink /D "E\FolderNameOnAnotherDisk\subfolder\sub ...


Views: 178 Likes: 85
Dot Net Core 3.1 Link Tag Helpers not Clickable
Category: .Net 7

Problem When developing in Asp.Net Core 3.1 and the links (Asp.Net Core Tag Hel ...


Views: 434 Likes: 100
The framework 'Microsoft.AspNetCore.App' version'3 ...
Category: Docker

Question How do you resolve the Error The framework 'Microsoft.AspNetC ...


Views: 1448 Likes: 146
Why is dotnet watch run not showing changes in the ...
Category: .Net 7

Question Why is <span style="background-color # ...


Views: 0 Likes: 56
How to Host DNX,DNU,DotNet Core CR in IIS
Category: Servers

Follow the steps below to host DNX/DNU based application in IIS.1. I ...


Views: 0 Likes: 25
How to install DotNet 8 runtime on Linux Ubuntu
Category: .NET 7

Question How do I install dotnet core 8 runtime on linux ubuntu?Answer Follow the steps ...


Views: 0 Likes: 22
 The .NET Stacks #8: functional C# 9, .NET Foundation nominees, Azure community, more!
The .NET Stacks #8 functional C# 9, .NET Foundat ...

This is an archive of my weekly (free!) newsletter, -The .NET Stacks-. Consider subscribing today to get this content right away! Subscribers don’t have to wait a week to receive the content.On tap this weekC# 9 a functionally better releaseThe .NET Foundation nominees are out!Dev Discussions Michael CrumpCommunity roundupC# 9 a functionally better releaseI’ve been writing a lot about C# 9 lately. No, seriously a lot. This week I went a little nuts with three posts I talked about records, pattern matching, and top-level programs. I’ve been learning a ton, which is always the main goal, but what’s really interesting is how C# is starting to blur the lines between object-oriented and functional programming. Throughout the years, we’ve seen some FP concepts visit C#, but I feel this release is really kicking it up a notch.In the not-so-distant past, discussing FP and OO meant putting up with silly dogmatic arguments that they have to be mutually exclusive. It isn’t hard to understand why traditional concepts of OO constructs are grouping data and behavior (state) in single mutable objects, and FP draws a hard line between data and behavior in the name of purity and minimizing side effects (immutability by default).So, typically as a .NET developer, this left you with two choices C#, .NET’s flagship language, or F#, a wonderful functional language that is concise (no curlies or semi-colons and great type inference), convenient (functions as first-class objects), and has default immutability.However, this is no longer a binary choice. For example, let’s look at a blog post from a few years ago that maps C# concepts to F# concepts.C#/OO has variables, F#/FP has immutable values. C# 9 init-only properties and records bring that ability to C#.C# has statements, F# has expressions. C# 8 introduced switch expressions and enhanced pattern matching, and has more expressions littered throughout the language now.C# has objects with methods, F# has types and functions. C# 9 records are also blurring the line in this regard.So here we are, just years after wondering if F# will ever take over C#, we see people wondering the exact opposite as Isaac Abraham asks will C# replace F#? (Spoiler alert no.)There is definitely pushback in the community from C# 8 purists, to which I say why not both? You now have the freedom to “bring in” the value of functional programming, while doing it in a familiar language. You can bring in these features, along with C#’s compatibility. These changes will not break the language. And if they don’t appeal to you, you don’t have to use them. (Of course, mixing FP and OO in C# is not always graceful and is definitely worth mentioning.)This isn’t a C# vs F# rant, but it comes down to this is C# with functional bits “good enough” because of your team’s skillset, comfort level, and OO needs? Or do you need a clean break, and immutability by default? As for me, I enjoy seeing these features gradually introduced. For example, C# 9 records allow you to build immutable structures but the language isn’t imposing this on you for all your objects. You need to opt in.A more nuanced question to ask is will C#’s functional concepts ever overpower the language and tilt the scales in FP’s direction? Soon, I’ll be interviewing Phillip Carter (the PM for F# at Microsoft) and am curious to hear what he has to say about it. Any questions? Let me know soon and I’ll be sure to include them.The .NET Foundation nominees are outThis week, the .NET Foundation announced the Board of Director nominees for the 2020 campaign. I am familiar with most of these folks (a few are subscribers, hi!)—it’s a very strong list and you probably can’t go wrong with anyone. I’d encourage you to look at the list and all their profiles to see who you’d like to vote for (if you are a member). If not, you can apply for membership. Or, if you’re just following the progress of the foundation, that’s great too.I know I’ve talked a lot about the Foundation lately, but this is an important moment for the .NET Foundation. The luster has worn off and it’s time to address the big questions what exactly is the Foundation responsible for? Where is the line between “independence” and Microsoft interests? When OSS projects collide with Microsoft interests, what is the process to work through it? And will the Foundation commit itself to open communication and greater transparency?As for me, these are the big questions I hope the nominees are thinking about, among other things.Dev Discussions Michael CrumpIf you’ve worked on Azure, you’ve likely come across Michael Crump’s work. He started Azure Tips and Tricks, a collection of tips, videos, and talks—if it’s Azure, it’s probably there. He also runs a popular Twitch stream where he talks about various topics.I caught up with Michael to talk about how he got to working on Azure at Microsoft, his work for the developer community, and his programming advice.My crack team of researchers tell me that you were a former Microsoft Silverlight MVP. Ah, memories. Do you miss it?Ah, yes. I was a Microsoft MVP for 4 years, I believe. I spent a lot of time working with Silverlight because, at that time, I was working in the medical field and a lot of our doctors used Macs. Since I was a C# WinForms/WPF developer, I jumped at the chance to start using those skillsets for code that would run on PCs and Macs.you walk me through your path to Microsoft, and what you do at Microsoft now?I started in Mac tech support because after graduating college, Mac tech support agents were getting paid more than PC agents (supply and demand, I guess!). Then, I was a full-time software developer for about 8 years. I worked in the medical field and created a calculator that determined what amount of vitamins our pre-mature babies should take.Well, after a while, the stress got to me and I discovered my love for teaching and started a job at Telerik as a developer advocate. Then, the opportunity came at Microsoft for a role to educate and inspire application developers. So my role today consists of developer content in many forms, and helping to set our Tier 1 event strategy for app developers.Tell us a little about Azure Tips and Tricks. What motivated you to get started, and how can people get involved?Azure Tips and Tricks was created because I’d find a thing or two about Azure, and forget how to do it again. It was originally designed as something just for me but many blog aggregators starting picking up on the posts and we decided to go big with it—from e-books, blog posts, videos, conference talks and stickers.The easiest way to contribute is by clicking on the Edit Page button at the bottom of each page. You can also go to http//source.azuredev.tips to learn more.What made you get into Twitch? What goes on in your channel?I loved the ability to actually code and have someone watch you and help you code. The interactivity aspect and seeing the same folks come back gets you hooked.The stream is broken down into three streams a weekAzure Tips and Tricks, every Wednesday at 1 PM PST (Pacific Standard Time, America)Live Interviews with Developers, every Friday at 9 AM PST (Pacific Standard Time, America)Live coding/Security Sunday streams, Sundays at 1030 AM PST (Pacific Standard Time, America)What is your one piece of programming advice?I actually published a list of my top 12 things every developer should know.My top one would probably be to learn a different programming language (other than your primary language). Simply put, it broadens your perspective and permits a deeper understanding of how a computer and programming languages work.This is only an excerpt of my talk with Michael. Read the full interview over at my website.Community roundupAn extremely busy week, full of great content!MicrosoftAnnouncementsAKS now supports confidential workloads.The Edge team announces the storage access API.Microsoft introduces the Text Analytics for Health APIs.Pratik Nadagouda talks about updates to the Git experience in Visual Studio.Eric Boyd shows off new Azure Cognitive Services capabilities.The .NET Foundation has the nominees set for the 2020 campaign.VideosThe Visual Studio Toolbox begins a series on performance profiling and continues their series on finding code in Visual Studio.The Xamarin Show discusses App Center and App Insights.Data Exposed continues their “why Azure SQL is best for devs” series.So many community standups we have the Languages & Runtime one, Entity Framework, and ASP.NET Core.Blog postsJason Freeberg continues his Zero to Hero with App Service series.Miguel Ramos dives into WinUI 3 in desktop apps.Jayme Singleton runs through the .NET virtual events in July.Leonard Lobel highlights the Azure CosmosDB change feed.Community BlogsASP.NET CoreChristian Nagel walks through local users with ASP.NET Core.Andrew Lock continues talking about adding an endpoint graph to ASP.NET Core..Thomas Ardal adds Razor runtime compilation for ASP.NET Core.Anthony Giretti exposes proto files in a lightweight gRPC service.Neel Bhatt introduces event sourcing in .NET Core.Dominick Baier talks about flexible access token validation in ASP.NET Core.The .NET Rocks podcast talks about ASP.NET Core Endpoints with Steve Smith.The ON.NET show discusses SignalR.BlazorWael Kdouh secures a Blazor WebAssembly Application With Azure Active Directory.Jon Hilton discusses Blazor validation logic on the client and the server.Marinko Spasojevic consumes a web API with Blazor WebAssembly.Matthew Jones continues writing Minesweeper for Blazor Web Assembly.Entity FrameworkKhalid Abuhakmeh talks about adding custom database functions for EF Core.Jon P. Smith discusses soft deleting data with Global Query Filters in EF Core.LanguagesDave Brock goes deep on C# 9, with records, pattern matching, and top-level programs.Ian Griffiths continues his series on C# 8 nullable references with conditional post-conditions..Khalid Abuhakmeh walks through reading from a file in C#.AzureJoseph Guadagno uses Azure Key Vault to secure Azure Functions (hi, Joe!).Visual Studio Magazine walks through Azure Machine Learning Studio Web.Damien Bowden walks through using external inputs in Azure Durable Functions.Azure Tips and Tricks has new content about Azure certifications for developers.Jason Gaylord discusses adding Azure feature flags to client applications.XamarinSimon Bisson pontificates on .NET MAUI and the future of Xamarin.Leomaris Reyes uses biometric identification in Xamarin.Forms.Kym Phillpotts creates a pizza shop in Xamarin.Forms.The Xamarin Podcast discusses Xamarin.Forms 4.7 and other topics.ToolsJetBrains introduces the .NET Guide.Jason Gaylord shows us how to create and delete branches in Visual Studio Code.Mike Larah uses custom browser configurations with Visual Studio.Muhammad Rehan Saeed shows us how to publish NuGet packages quickly.Patrick Smacchia talks about his top 10 Visual Studio refactoring tips.Bruce Cottman asks if GitHub Actions will kill off Jenkins.ProjectsOren Eini releases CosmosDB Profiler 1.0.Manuel Grundner introduces his new Tasty project, an effort to bring the style of his favorite test frameworks to .NET.Community podcasts and videosScott Hanselman shows off his Raspberry Pi and shows off how you can run .NET Notebooks and .NET Interactive on it, talks about Git pull requests, shows off Git 101 basics, and walks through setting up a prompt with Git, Windows Terminal, PowerShell, and Cascadia Code.The ASP.NET Monsters talk about NodaTime and API controllers.The 6-Figure Developer podcast talks about AI with Matthew Renze.The No Dogma podcast talks with Bill Wagner about .NET 5 and unifying .NET.The Coding Blocks podcast studies The DevOps Handbook.New subscribers and feedbackHas this email been forwarded to you? Welcome! I’d love for you to subscribe and join the community. I promise to guard your email address with my life.I would love to hear any feedback you have for The .NET Stacks! My goal is to make this the one-stop shop for weekly updates on developing in the .NET ecosystem, so I look forward to any feedback you can provide. You can directly reply to this email, or talk to me on Twitter as well. See you next week!


 The .NET Stacks #32: ?? SSR is cool again
The .NET Stacks #32 ?? SSR is cool again

Good morning and happy Monday! We’ve got a few things to discuss this weekThe new/old hotness HTML over the wireXamarin.Forms 5.0 released this weekQuick break how to explaining C# string interpolation to the United States SenateLast week in the .NET worldThe new/old hotness server-side renderingOver the holidays, I was intrigued by the release of the Hotwire project, from the folks at BasecampHotwire is an alternative approach to building modern web applications without using much JavaScript by sending HTML instead of JSON over the wire. This makes for fast first-load pages, keeps template rendering on the server, and allows for a simpler, more productive development experience in any programming language, without sacrificing any of the speed or responsiveness associated with a traditional single-page application.Between this and other tech such as Blazor Server, the “DOM over the wire” movement is in full force. It’s a testament to how bloated and complicated the front end has become.Obviously, rendering partial HTML over the wire isn’t anything new at all—especially to us .NET developers—and it’s sure to bring responses like “Oh, you mean what I’ve been doing the last 15 years?” As much as I enjoy the snark, it’s important to not write it off as the front-end community embracing what we’ve become comfortable with, as the technical details differ a bit—and we can learn from it. For example, it looks like instead of Hotwire working with DOM diffs over the wire, it streams partial updates over WebSocket while dividing complex pages into separate components, with an eye on performance. I wonder how Blazor Server would have been architected if this was released 2 years ago.Xamarin.Forms 5.0 released this weekThis week, the Xamarin team released the latest stable release of Xamarin.Forms, version 5.0, which will be supported through November 2022. There’s updates for App Themes, Brushes, and SwipeView, among other things. The team had a launch party. Also, David Ramel writes that this latest version drops support for Visual Studio 2017. Updates to Android and iOS are only delivered to 2019, and pivotal for getting the latest updates from Apple and Google.2021 promises to be a big year for Xamarin, as they continue preparing to join .NET 6—as this November, Xamarin.Forms evolves into MAUI (the .NET Multi-Platform App UI). This means more than developing against iPhones and Android devices, of course. With .NET 6 this also includes native UIs for iOS, Android, and desktops. As David Ramel also writes, Linux will not be supported out of the gate and VS Code support will be quite limited.As he also writes, in a community standup David Ortinau clarifies that MAUI is not a rewrite.So my hope and expectation, depending on the complexity of your projects, is you can be up and going within days … It’s not rewrites – it’s not a rewrite – that’s probably the biggest message that I should probably say over and over and over again. You’re not rewriting your application.Quick break how to explain C# string interpolation to the United States SenateDid I ever think C# string interpolation would make it to the United States Senate? No, I most certainly did not. But last month, that’s what happened as former Cybersecurity and Infrastructure Security Agency (CISA) head Chris Krebs explained a bugIt’s on page 20 … it says ‘There is no permission to {0}’. … Something jumped out at me, having worked at Microsoft. … The election-management system is coded with the programming language called C#. There is no permission to {0}’ is placeholder for a parameter, so it may be that it’s just not good coding, but that certainly doesn’t mean that somebody tried to get in there a 0. They misinterpreted the language in what they saw in their forensic audit.It appears that the election auditors were scared by something like thisConsole.WriteLine("There is no permission to {0}"); To us, we know it’s just a log statement that verifies permission checks are working. It should have been coded using one of the following lines of codeConsole.WriteLine("There is no permission to {0}", permission); Console.WriteLine($"There is no permission to {permission}"); I’m available to explain string interpolation to my government for a low, low rate of $1000 an hour. All they had to do was ask.?? Last week in the .NET world?? The Top 4Josef Ottosson works with polymorphic deserialization with System.Text.Json.Shahed Chowdhuri works with init-only setters in C# 9.Khalid Abuhakmeh writes about EF Core 5 interceptors.Over at the AWS site, the folks at DraftKings have a nice read about modernizing with .NET Core and AWS.?? AnnouncementsWinUI 3 Preview 3 has been released.David Ortinau announces the arrival of Xamarin.Forms 5.0.Microsoft Learn has a new module on learning Python.James Newton-King releases a new Microsoft doc, Code-first gRPC services and clients with .NET.Phillip Carter brings attention to a living F# coding conventions document.Patrick Svensson releases version 0.37 of Spectre.Console.The Azure SDK team released new .NET packages to simplify migrations using Newtonsoft.Json and/or Microsoft.Spatial.The EF Core team releases EFCore.NamingConventions 5.0.1, which fixes issues with owned entities and table splitting in 5.0.0.?? Community and eventsChris Noring introduces GitHub’s web dev for beginners tutorials.Niels Swimberghe rolls out two utilities written in Blazor a GZIP compressor/decompressor, and a .NET GUID generator.ErikEJ writes about some free resources for EF 5.The Xamarin community standup is a launch party for Xamarin.Forms 5.The .NET Docs Show talks to co-host David Pine about his localization project.Shahed Chowdhuri previews a new C# A-Z project and a Marvel cinematic visualization app.Chris Woodruff kicks of an ASP.NET 5 Web API blog series.VS Code Day is slated for January 27.?? Web developmentPeter Vogel writes about displaying lists efficiently in Blazor.Over at Code Maze, using the API gateway pattern in .NET to encapsulate microservices.David Fowler notes that web socket compression is coming to .NET 6.Chris Noring manages configuration in ASP.NET Core.Marinko Spasojevic signs in with Google using Angular and ASP.NET Core Web API.Damien Bowden works with Azure AD access token lifetime policy management in ASP.NET Core.Paul Michaels views server variables in ASP.NET Core.Sahan Serasinghe writes about using Web Sockets with ASP.NET Core.?? The .NET platformRichard Reedy talks about the Worker Service in .NET Core.Marco Minerva develops desktop apps with .NET 5.Jimmy Bogard works with ActivitySource and ActivityListener in .NET 5.Nikola Zivkovic introduces machine learning with ML.NET.Nick Randolph works with missing files in a multi-targeted project.Stefan Koell writes about migrating Royal TS from WinForms to .NET 5.? The cloudAndrew Lock auto-assigns issues using a GitHub Action.Richard Reedy builds a chatbot to order a pizza.Dave Brock uses the Microsoft Bot Framework to analyze emotion with the Azure Face API.Jonathan Channon uses GCP Cloud Functions with F#.Justin Yoo writes about using Azure EventGrid.Mark Heath writes about bulk uploading files to Azure Blob Storage with the Azure CLI.Daniel Krzyczkowski continues his series on writing an ASP.NET Core API secured by Azure AD B2C.Paul Michaels schedules message delivery with Azure Service Bus.?? LanguagesRick Strahl works with blank zero values in .NET number format strings.David McCarter analyzes code for issues in .NET 5.Khalid Abuhakmeh plays audio files with .NET.Daniel Bachler talks about what he wishes he knew when learning F#.Michal Niegrzybowski writes about signaling in WebRTC with Ably and Fable.Mark-James McDougall talks about why he’s learning F# in 2021.?? ToolsJason Robert creates a serverless Docker image.Stephen Cleary kicks off a series around asynchronous messaging.Michal Bialecki recaps useful SQL statements when writing EF Core migrations.Derek Comartin splits up a monolith into microservices.Frank Boucher creates a CI/CD deployment solution for a Docker project.Alex Orlov writes about using TLS 1.3 for IMAP and SMTP connections through Mailbee.NET.Brad Beggs writes about using vertical rulers in VS Code.Tim Cochran writes about maximizing developer effectiveness.?? XamarinDavid Ramel writes how Xamarin.Forms won’t be on Linux or VS Code for MAUI in .NET 6, and also mentions that Xamarin.Forms 5 is dropping Visual Studio 2017 support.Leomaris Reyes writes about Xamarin Essentials.Anbu Mani works with infinite scrolling in Xamarin.Forms.Matthew Robbins embeds a JS interpreter into Xamarin apps with Jint.?? PodcastsScott Hanselman talks to Amanda Silver about living through 2020 as a remote developer.The 6-Figure Developer Podcast talks with Phillip Carter about F# and functional programming.The Azure DevOps Podcast talks with Sam Nasr about SQL Server for developers.?? VideosVisual Studio Toolbox talks about the Azure App Insights Profiler.The ASP.NET Monsters talk with Andrew Stanton-Nurse.Gerald Versluis secures a Xamarin app with fingerprint or face recognition.James Montemagno makes another Xamarin.Forms 101 video.At Technology and Friends, David Giard talks to Javier Lozano about virtual conferences.Jeff Fritz works on ASP.NET Core MVC and also APIs with ASP.NET Core.ON.NET discusses cross-platform .NET development with OmniSharp.


Trying out MongoDB with EF Core using Testcontainers
Trying out MongoDB with EF Core using Testcontaine ...

Helping developers use both relational and non-relational databases effectively was one of the original tenets of EF Core. To this end, there has been an EF Core database provider for Azure Cosmos DB document databases for many years now. Recently, the EF Core team has been collaborating with engineers from MongoDB to bring support for MongoDB to EF Core. The initial result of this collaboration is the first preview release of the MongoDB provider for EF Core. In this post, we will try out the MongoDB provider for EF Core by using it to Map a C# object model to documents in a MongoDB database Use EF to save some documents to the database Write LINQ queries to retrieve documents from the database Make changes to a document and use EF’s change tracking to update the document The code shown in this post can be found on GitHub. Testcontainers It’s very easy to get a MongoDB database in the cloud that you can use to try things out. However, Testcontainers is another way to test code with different database systems which is particularly suited to Running automated tests against the database Creating standalone reproductions when reporting issues Trying out new things with minimal setup Testcontainers are distributed as NuGet packages that take care of running a container containing a configured ready-to-use database system. The containers use Docker or a Docker-alternative to run, so this may need to be installed on your machine if you don’t already have it. See Welcome to Testcontainers for .NET! for more details. Other than starting Docker, you don’t need to do anything else except import the NuGet package. The C# project We’ll use a simple console application to try out MongoDB with EF Core. This project needs two package references MongoDB.EntityFrameworkCore to install the EF Core provider. This package also transitives installs the common EF Core packages and the MongoDB.Driver package which is used by the EF Provider to access the MongoDB database. Testcontainers.MongoDb to install the pre-defined Testcontainer for MongoDB. The full csproj file looks like this <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <RootNamespace /> </PropertyGroup> <ItemGroup> <PackageReference Include="Testcontainers.MongoDB" Version="3.5.0" /> <PackageReference Include="MongoDB.EntityFrameworkCore" Version="7.0.0-preview.1" /> </ItemGroup> </Project> Remember, the full project is available to download from GitHUb. The object model We’ll map a simple object model of customers and their addresses public class Customer { public Guid Id { get; set; } public required string Name { get; set; } public required Species Species { get; set; } public required ContactInfo ContactInfo { get; set; } } public class ContactInfo { public required Address ShippingAddress { get; set; } public Address? BillingAddress { get; set; } public required PhoneNumbers Phones { get; set; } } public class PhoneNumbers { public PhoneNumber? HomePhone { get; set; } public PhoneNumber? WorkPhone { get; set; } public PhoneNumber? MobilePhone { get; set; } } public class PhoneNumber { public required int CountryCode { get; set; } public required string Number { get; set; } } public class Address { public required string Line1 { get; set; } public string? Line2 { get; set; } public string? Line3 { get; set; } public required string City { get; set; } public required string Country { get; set; } public required string PostalCode { get; set; } } public enum Species { Human, Dog, Cat } Since MongoDB works with documents, we’re going to map this model to a top level Customer document, with the addresses and phone numbers embedded in this document. We’ll see how to do this in the next section. Creating the EF model EF works by building a model of the mapped CLR types, such as those for Customer, etc. in the previous section. This model defines the relationships between types in the model, as well as how each type maps to the database. Luckily there is not much to do here, since EF uses a set of model building conventions that generate a model based on input from both the model types and the database provider. This means that for relational databases, each type gets mapped to a different table by convention. For document databases like Azure CosmosDB and now MongoDB, only the top-level type (Customer in our example) is mapped to its own document. Other types referenced from the top-level types are, by-convention, included in the main document. This means that the only thing EF needs to know to build a model is the top-level type, and that the MongoDB provider should be used. We do this by defining a type that extends from DbContext. For example public class CustomersContext DbContext { private readonly MongoClient _client; public CustomersContext(MongoClient client) { _client = client; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseMongoDB(_client, "efsample"); public DbSet<Customer> Customers => Set<Customer>(); } In this DbContext class UseMongoDB is called, passing in the client driver and the database name. This tells EF Core to use the MongoDB provider when building the model and accessing the database. A DbSet<Customer> property that defines the top-level type for which documents should be modeled. We’ll see later how to create the MongoClient instance and use the DbContext. When we do, examining the model DebugView shows this Model EntityType ContactInfo Owned Properties CustomerId (no field, Guid) Shadow Required PK FK AfterSaveThrow Navigations BillingAddress (Address) ToDependent ContactInfo.BillingAddress#Address (Address) Phones (PhoneNumbers) ToDependent PhoneNumbers ShippingAddress (Address) ToDependent ContactInfo.ShippingAddress#Address (Address) Keys CustomerId PK Foreign keys ContactInfo {'CustomerId'} -> Customer {'Id'} Unique Ownership ToDependent ContactInfo Cascade EntityType ContactInfo.BillingAddress#Address (Address) CLR Type Address Owned Properties ContactInfoCustomerId (no field, Guid) Shadow Required PK FK AfterSaveThrow City (string) Required Country (string) Required Line1 (string) Required Line2 (string) Line3 (string) PostalCode (string) Required Keys ContactInfoCustomerId PK Foreign keys ContactInfo.BillingAddress#Address (Address) {'ContactInfoCustomerId'} -> ContactInfo {'CustomerId'} Unique Ownership ToDependent BillingAddress Cascade EntityType ContactInfo.ShippingAddress#Address (Address) CLR Type Address Owned Properties ContactInfoCustomerId (no field, Guid) Shadow Required PK FK AfterSaveThrow City (string) Required Country (string) Required Line1 (string) Required Line2 (string) Line3 (string) PostalCode (string) Required Keys ContactInfoCustomerId PK Foreign keys ContactInfo.ShippingAddress#Address (Address) {'ContactInfoCustomerId'} -> ContactInfo {'CustomerId'} Unique Ownership ToDependent ShippingAddress Cascade EntityType Customer Properties Id (Guid) Required PK AfterSaveThrow ValueGenerated.OnAdd Name (string) Required Species (Species) Required Navigations ContactInfo (ContactInfo) ToDependent ContactInfo Keys Id PK EntityType PhoneNumbers Owned Properties ContactInfoCustomerId (no field, Guid) Shadow Required PK FK AfterSaveThrow Navigations HomePhone (PhoneNumber) ToDependent PhoneNumbers.HomePhone#PhoneNumber (PhoneNumber) MobilePhone (PhoneNumber) ToDependent PhoneNumbers.MobilePhone#PhoneNumber (PhoneNumber) WorkPhone (PhoneNumber) ToDependent PhoneNumbers.WorkPhone#PhoneNumber (PhoneNumber) Keys ContactInfoCustomerId PK Foreign keys PhoneNumbers {'ContactInfoCustomerId'} -> ContactInfo {'CustomerId'} Unique Ownership ToDependent Phones Cascade EntityType PhoneNumbers.HomePhone#PhoneNumber (PhoneNumber) CLR Type PhoneNumber Owned Properties PhoneNumbersContactInfoCustomerId (no field, Guid) Shadow Required PK FK AfterSaveThrow CountryCode (int) Required Number (string) Required Keys PhoneNumbersContactInfoCustomerId PK Foreign keys PhoneNumbers.HomePhone#PhoneNumber (PhoneNumber) {'PhoneNumbersContactInfoCustomerId'} -> PhoneNumbers {'ContactInfoCustomerId'} Unique Ownership ToDependent HomePhone Cascade EntityType PhoneNumbers.MobilePhone#PhoneNumber (PhoneNumber) CLR Type PhoneNumber Owned Properties PhoneNumbersContactInfoCustomerId (no field, Guid) Shadow Required PK FK AfterSaveThrow CountryCode (int) Required Number (string) Required Keys PhoneNumbersContactInfoCustomerId PK Foreign keys PhoneNumbers.MobilePhone#PhoneNumber (PhoneNumber) {'PhoneNumbersContactInfoCustomerId'} -> PhoneNumbers {'ContactInfoCustomerId'} Unique Ownership ToDependent MobilePhone Cascade EntityType PhoneNumbers.WorkPhone#PhoneNumber (PhoneNumber) CLR Type PhoneNumber Owned Properties PhoneNumbersContactInfoCustomerId (no field, Guid) Shadow Required PK FK AfterSaveThrow CountryCode (int) Required Number (string) Required Keys PhoneNumbersContactInfoCustomerId PK Foreign keys PhoneNumbers.WorkPhone#PhoneNumber (PhoneNumber) {'PhoneNumbersContactInfoCustomerId'} -> PhoneNumbers {'ContactInfoCustomerId'} Unique Ownership ToDependent WorkPhone Cascade Looking at this model, it can be seen that EF created owned entity types for the ContactInfo, Address, PhoneNumber and PhoneNumbers types, even though only the Customer type was referenced directly from the DbContext. These other types were discovered and configured by the model-building conventions. Create the MongoDB test container We now have a model and a DbContext. Next we need an actual MongoDB database, and this is where Testcontainers come in. There are Testcontainers available for many different types of database, and they all work in a very similar way. That is, a container is created using the appropriate DbBuilder, and then that container is started. For example await using var mongoContainer = new MongoDbBuilder() .WithImage("mongo6.0") .Build(); await mongoContainer.StartAsync(); And that’s it! We now have a configured, clean MongoDB instance running locally with which we can do what we wish, before just throwing it away. Save data to MongoDB Let’s use EF Core to write some data to the MongoDB database. To do this, we’ll need to create a DbContext instance, and for this we need a MongoClient instance from the underlying MongoDB driver. Often, in a real app, the MongoClient instance and the DbContext instance will be obtained using dependency injection. For the sake of simplicity, we’ll just new them up here var mongoClient = new MongoClient(mongoContainer.GetConnectionString()); await using (var context = new CustomersContext(mongoClient)) { // ... } Notice that the Testcontainer instance provides the connection string we need to connect to our MongoDB test database. To save a new Customer document, we’ll use Add to start tracking the document, and then call SaveChangesAsync to insert it into the database. await using (var context = new CustomersContext(mongoClient)) { var customer = new Customer { Name = "Willow", Species = Species.Dog, ContactInfo = new() { ShippingAddress = new() { Line1 = "Barking Gate", Line2 = "Chalk Road", City = "Walpole St Peter", Country = "UK", PostalCode = "PE14 7QQ" }, BillingAddress = new() { Line1 = "15a Main St", City = "Ailsworth", Country = "UK", PostalCode = "PE5 7AF" }, Phones = new() { HomePhone = new() { CountryCode = 44, Number = "7877 555 555" }, MobilePhone = new() { CountryCode = 1, Number = "(555) 2345-678" }, WorkPhone = new() { CountryCode = 1, Number = "(555) 2345-678" } } } }; context.Add(customer); await context.SaveChangesAsync(); } If we look at the JSON (actually, BSON, which is a more efficient binary representation for JSON documents) document created in the database, we can see it contains nested documents for all the contact information. This is different from what EF Core would do for a relational database, where each type would have been mapped to its own top-level table. { "_id" "CSUUID(\"9a97fd67-515f-4586-a024-cf82336fc64f\")", "Name" "Willow", "Species" 1, "ContactInfo" { "BillingAddress" { "City" "Ailsworth", "Country" "UK", "Line1" "15a Main St", "Line2" null, "Line3" null, "PostalCode" "PE5 7AF" }, "Phones" { "HomePhone" { "CountryCode" 44, "Number" "7877 555 555" }, "MobilePhone" { "CountryCode" 1, "Number" "(555) 2345-678" }, "WorkPhone" { "CountryCode" 1, "Number" "(555) 2345-678" } }, "ShippingAddress" { "City" "Walpole St Peter", "Country" "UK", "Line1" "Barking Gate", "Line2" "Chalk Road", "Line3" null, "PostalCode" "PE14 7QQ" } } } Using LINQ queries EF Core supports LINQ for querying data. For example, to query a single customer using (var context = new CustomersContext(mongoClient)) { var customer = await context.Customers.SingleAsync(c => c.Name == "Willow"); var address = customer.ContactInfo.ShippingAddress; var mobile = customer.ContactInfo.Phones.MobilePhone; Console.WriteLine($"{customer.Id} {customer.Name}"); Console.WriteLine($" Shipping to {address.City}, {address.Country} (+{mobile.CountryCode} {mobile.Number})"); } Running this code results in the following output 336d4936-d048-469e-84c8-d5ebc17754ff Willow Shipping to Walpole St Peter, UK (+1 (555) 2345-678) Notice that the query pulled back the entire document, not just the Customer object, so we are able to access and print out the customer’s contact info without going back to the database. Other LINQ operators can be used to perform filtering, etc. For example, to bring back all customers where the Species is Dog var customers = await context.Customers .Where(e => e.Species == Species.Dog) .ToListAsync(); Updating a document By default, EF tracks the object graphs returned from queries. Then, when SaveChanges or SaveChangesAsync is called, EF detects any changes that have been made to the document and sends an update to MongoDB to update that document. For example using (var context = new CustomersContext(mongoClient)) { var baxter = (await context.Customers.FindAsync(baxterId))!; baxter.ContactInfo.ShippingAddress = new() { Line1 = "Via Giovanni Miani", City = "Rome", Country = "IT", PostalCode = "00154" }; await context.SaveChangesAsync(); } In this case, we’re using FindAsync to query a customer by primary key–a LINQ query would work just as well. After that, we change the shipping address to Rome, and call SaveChangesAsync. EF detects that only the shipping address for a single document has been changed, and so sends a partial update to patch the updated address into the document stored in the MongoDB database. Going forward So far, the MongoDB provider for EF Core is only in its first preview. Full CRUD (creating, reading, updating, and deleting documents) is supported by this preview, but there are some limitations. See the readme on GitHub for more information, and for places to ask questions and file bugs. Learn more To learn more about EF Core and MongoDB See the EF Core documentation to learn more about using EF Core to access all kinds of databases. See the MongoDB documentation to learn more about using MongoDB from any platform. Watch Introducing the MongoDB provider for EF Core on the .NET Data Community Standup. Watch the upcoming Announcing MongoDB Provider for Entity Framework Core on the MongoDB livestream. Summary We used Testcontainers to try out the first preview release of the MongoDB provider for EF Core. Testcontainers allowed us to test MongoDB with very minimal setup, and we were able to create, query, and update documents in the MongoDB database using EF Core. The post Trying out MongoDB with EF Core using Testcontainers appeared first on .NET Blog.


Google SEO Ranking How to Rank in Google
Category: Technology

How to Rank in Google SEO PlanAnswersYour home page is impo ...


Views: 332 Likes: 86
Performance Improvements in ASP.NET Core 8
Performance Improvements in ASP.NET Core 8

ASP.NET Core 8 and .NET 8 bring many exciting performance improvements. In this blog post, we will highlight some of the enhancements made in ASP.NET Core and show you how they can boost your web app’s speed and efficiency. This is a continuation of last year’s post on Performance improvements in ASP.NET Core 7. And, of course, it continues to be inspired by Performance Improvements in .NET 8. Many of those improvements either indirectly or directly improve the performance of ASP.NET Core as well. Benchmarking Setup We will use BenchmarkDotNet for many of the examples in this blog post. To setup a benchmarking project Create a new console app (dotnet new console) Add a Nuget reference to BenchmarkDotnet (dotnet add package BenchmarkDotnet) version 0.13.8+ Change Program.cs to var summary = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(); Add the benchmarking code snippet below that you want to run Run dotnet run -c Release and enter the number of the benchmark you want to run when prompted Some of the benchmarks test internal types, and a self-contained benchmark cannot be written. In those cases we’ll either reference numbers that are gotten by running the benchmarks in the repository (and link to the code in the repository), or we’ll provide a simplified example to showcase what the improvement is doing. There are also some cases where we will reference our end-to-end benchmarks which are public at https//aka.ms/aspnet/benchmarks. Although we only display the last few months of data so that the page will load in a reasonable amount of time. Servers We have 3 server implementations in ASP.NET Core; Kestrel, Http.Sys, and IIS. The latter two are only usable on Windows and share a lot of code. Server performance is extremely important because it’s what processes incoming requests and forwards them to your application code. The faster we can process a request, the faster you can start running application code. Kestrel Header parsing is one of the first parts of processing done by a server for every request. Which means the performance is critical to allow requests to reach your application code as fast as possible. In Kestrel we read bytes off the connection into a System.IO.Pipelines.Pipe which is essentially a list of byte[]s. When parsing headers we are reading from that list of byte[]s and have two different code paths. One for when the full header is inside a single byte[] and another for when a header is split across multiple byte[]s. dotnet/aspnetcore#45044 updated the second (slower) code path to avoid allocating a byte[] when parsing the header, as well as optimizes our SequenceReader usage to mostly use the underlying ReadOnlySequence<byte> which can be faster in some cases. This resulted in a ~18% performance improvement for multi-span headers as well as making it allocation free which helps reduce GC pressure. The following microbenchmark is using internal types in Kestrel and isn’t easy to isolate as a minimal sample. For those interested it is located with the Kestrel source code and was run before and after the change. Method Mean Op/s Gen 0 Allocated MultispanUnicodeHeader – Before 573.8 ns 1,742,893.2 – 48 B MultispanUnicodeHeader – After 484.9 ns 2,062,450.8 – – Below is an allocation profile of an end-to-end benchmark we run on our CI showing the different with this change. We reduced the byte[] allocations of the scenario by 73%. From 7.8GB to 2GB (during the lifetime of the benchmark run). dotnet/aspnetcore#48368 replaced some internal custom vectorized code for ascii comparison checks with the new Ascii class in .NET 8. This allowed us to remove ~400 lines of code and take advantage of improvements like AVX512 and ARM AdvSIMD that are implemented in the Ascii code that we didn’t have in Kestrel’s implementation. Http.Sys Near the end of 7.0 we removed some extra thread pool dispatching in Kestrel that improved performance significantly. More details are in last years performance post. At the beginning of 8.0 we made similar changes to the Http.Sys server in dotnet/aspnetcore#44409. This improved our Json end to end benchmark by 11% from ~469k to ~522k RPS. Another change we made affects large responses especially in higher latency connections. dotnet/aspnetcore#47776 adds an on-by-default option to enable Kernel-mode response buffering. This allows application writes to be buffered in the OS layer regardless of whether the client connection has acked previous writes or not, and then the OS can optimize sending the data by parallelizing writes and/or sending larger chunks of data at a time. The benefits are clear when using connections with higher latency. To show a specific example we hosted a server in Sweden and a client in West Coast USA to create some latency in the connection. The following server code was used var builder = WebApplication.CreateBuilder(args); builder.WebHost.UseHttpSys(options => { options.UrlPrefixes.Add("http//+12345"); options.Authentication.Schemes = AuthenticationSchemes.None; options.Authentication.AllowAnonymous = true; options.EnableKernelResponseBuffering = true; // <-- new setting in 8.0 }); var app = builder.Build(); app.UseRouting(); app.MapGet("/file", () => { return TypedResults.File(File.Open("pathToLargeFile", FileMode.Open, FileAccess.Read)); }); app.Run(); The latency was around 200ms (round-trip) between client and server and the server was responding to client requests with a 212MB file. When setting HttpSysOptions.EnableKernelResponseBuffering to false the file download took ~11 minutes. And when setting it to true it took ~30 seconds to download the file. That’s a massive improvement, ~22x faster in this specific scenario! More details on how response buffering works can be found in this blog post. dotnet/aspnetcore#44561 refactors the internals of response writing in Http.Sys to remove a bunch of GCHandle allocations and conveniently removes a List<GCHandle> that was used to track handles for freeing. It does this by allocating and writing directly to NativeMemory when writing headers. By not pinning managed memory we are reducing GC pressure and helping reduce heap fragmentation. A downside is that we need to be extra careful to free the memory because the allocations are no longer tracked by the GC. Running a simple web app and tracking GCHandle usage shows that in 7.0 a small response with 4 headers was using 8 GCHandles per request, and when adding more headers it was using 2 more GCHandles per header. In 8.0 the same app was using only 4 GCHandles per request, regardless of the number of headers. dotnet/aspnetcore#45156 by @ladeak improved the implementation of HttpContext.Request.Headers.Keys and HttpContext.Request.Headers.Count in Http.Sys, which is also the same implementation used by IIS so double win. Before, those properties had generic implementations that used IEnumerable and linq expressions. Now they manually count and minimize allocations, making accessing Count completely allocation free. This benchmark uses internal types, so I’ll link to the microbenchmark source instead of providing a standalone microbenchmark. Before Method Mean Op/s Gen 0 Allocated CountSingleHeader 381.3 ns 2,622,896.1 0.0010 176 B CountLargeHeaders 3,293.4 ns 303,639.9 0.0534 9,032 B KeysSingleHeader 483.5 ns 2,068,299.5 0.0019 344 B KeysLargeHeaders 3,559.4 ns 280,947.4 0.0572 9,648 B After Method Mean Op/s Gen 0 Allocated CountSingleHeader 249.1 ns 4,014,316.0 – – CountLargeHeaders 278.3 ns 3,593,059.3 – – KeysSingleHeader 506.6 ns 1,974,125.9 – 32 B KeysLargeHeaders 1,314.6 ns 760,689.5 0.0172 2,776 B Native AOT Native AOT was first introduced in .NET 7 and only worked with console applications and a limited number of libraries. In .NET 8.0 we’ve improved the number of libraries that are supported in Native AOT as well as added support for ASP.NET Core applications. AOT apps can have minimized disk footprint, reduced startup times, and reduced memory demand. But before we talk about AOT more and show some numbers, we should talk about a prerequisite, trimming. Starting in .NET 6 trimming applications became a fully supported feature. Enabling this feature with <PublishTrimmed>true</PublishTrimmed> in your .csproj enables the trimmer to run during publish and remove code your application isn’t using. This can result in smaller deployed application sizes, useful in scenarios where you are running on memory constrained devices. Trimming isn’t free though, libraries might need to annotate types and method calls to tell the trimmer about code being used that the trimmer can’t determine, otherwise the trimmer might trim away code you’re relying on and your app won’t run as expected. The trimmer will raise warnings when it sees code that might not be compatible with trimming. Until .NET 8 the <TrimMode> property for publishing web apps was set to partial. This meant that only assemblies that explicitly stated they supported trimming would be trimmed. Now in 8.0, full is used for <TrimMode> which means all assemblies used by the app will be trimmed. These settings are documented in the trimming options docs. In .NET 6 and .NET 7 a lot of libraries weren’t compatible with trimming yet, notably ASP.NET Core libraries. If you tried to publish a simple ASP.NET Core app in 7.0 you would get a bunch of trimmer warnings because most of ASP.NET Core didn’t support trimming yet. The following is an ASP.NET Core app to show trimming in net7.0 vs. net8.0. All the numbers are for a windows publish. <Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFrameworks>net7.0;net8.0</TargetFrameworks> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> </Project> // dotnet publish --self-contained --runtime win-x64 --framework net7.0 -pPublishTrimmed=true -pPublishSingleFile=true --configuration Release var app = WebApplication.Create(); app.Run((c) => c.Response.WriteAsync("hello world")); app.Run(); TFM Trimmed Warnings App Size Publish duration net7.0 false 0 88.4MB 3.9 sec net8.0 false 0 90.9MB 3.9 sec net7.0 true 16 28.9MB 16.4 sec net8.0 true 0 17.3MB 10.8 sec In addition to no more warnings when publishing trimmed in net8.0, the app size is smaller because we’ve annotated more libraries so the linker can find more code that isn’t being used by the app. Part of annotating the libraries involved analyzing what code is being kept by the trimmer and changing code to improve what can be trimmed. You can see numerous PRs to help this effort; dotnet/aspnetcore#47567, dotnet/aspnetcore#47454, dotnet/aspnetcore#46082, dotnet/aspnetcore#46015, dotnet/aspnetcore#45906, dotnet/aspnetcore#46020, and many more. The Publish duration field was calculated using the Measure-Command in powershell (and deleting /bin/ and /obj/ between every run). As you can see, enabling trimming can increase the publish time because the trimmer has to analyze the whole program to see what it can remove, which isn’t a free operation. We also introduced two smaller versions of WebApplication if you want even smaller apps via CreateSlimBuilder and CreateEmptyBuilder. Changing the previous app to use CreateSlimBuilder // dotnet publish --self-contained --runtime win-x64 --framework net8.0 -pPublishTrimmed=true -pPublishSingleFile=true --configuration Release var builder = WebApplication.CreateSlimBuilder(args); var app = builder.Create(); app.Run((c) => c.Response.WriteAsync("hello world")); app.Run(); will result in an app size of 15.5MB. And then going one step further with CreateEmptyBuilder // dotnet publish --self-contained --runtime win-x64 --framework net8.0 -pPublishTrimmed=true -pPublishSingleFile=true --configuration Release var builder = WebApplication.CreateEmptyBuilder(new WebApplicationOptions() { Args = args }); var app = builder.Create(); app.Run((c) => c.Response.WriteAsync("hello world")); app.Run(); will result in an app size of 13.7MB, although in this case the app won’t work because there is no server implementation registered. So if we add Kestrel via builder.WebHost.UseKestrelCore(); the app size becomes 15MB. TFM Builder App Size net8.0 Create 17.3MB net8.0 Slim 15.5MB net8.0 Empty 13.7MB net8.0 Empty+Server 15.0MB Note that both these APIs are available starting in 8.0 and remove a lot of defaults so it’s more pay for play. Now that we’ve taken a small look at trimming and seen that 8.0 has more trim compatible libraries, let’s take a look at Native AOT. Just like with trimming, if your app/library isn’t compatible with Native AOT you’ll get warnings when building for Native AOT and there are additional limitations to what works in Native AOT. Using the same app as before, we’ll enable Native AOT by adding <PublishAot>true</PublishAot> to our csproj. TFM AOT App Size Publish duration net7.0 false 88.4MB 3.9 sec net8.0 false 90.9MB 3.9 sec net7.0 true 40MB 71.7 sec net8.0 true 12.6MB 22.7 sec And just like with trimming, we can test the WebApplication APIs that have less defaults enabled. TFM Builder App Size net8.0 Create 12.6MB net8.0 Slim 8.8MB net8.0 Empty 5.7MB net8.0 Empty+Server 7.8MB That’s pretty cool! A small net8.0 app is 90.9MB and when published as Native AOT it’s 12.6MB, or as low as 7.8MB (assuming we want a server, which we probably do). Now let’s take a look at some other performance characteristics of a Native AOT app; startup speed, memory usage, and RPS. In order to properly show E2E benchmark numbers we need to use a multi-machine setup so that the server and client processes don’t steal CPU from each other and we don’t have random processes running like you would for a local machine. I’ll be using our internal benchmarking infrastructure that makes use of the benchmarking tool crank and our aspnet-citrine-win and aspnet-citrine-lin machines for server and load respectively. Both machine specs are described in our benchmarks readme. And finally, I’ll be using an application that uses Minimal APIs to return a json payload. This app uses the Slim builder we showed earlier as well as sets <InvariantGlobalization>true</InvariantGlobalization> in the csproj. If we run the app without any extra settings crank –config https//raw.githubusercontent.com/aspnet/Benchmarks/main/scenarios/goldilocks.benchmarks.yml –config https//raw.githubusercontent.com/aspnet/Benchmarks/main/build/ci.profile.yml –config https//raw.githubusercontent.com/aspnet/Benchmarks/main/scenarios/steadystate.profile.yml –scenario basicminimalapivanilla –profile intel-win-app –profile intel-lin-load –application.framework net8.0 –application.options.collectCounters true This gives us a ~293ms startup time, 444MB working set, and ~762k RPS. If we run the same app but publish it as Native AOT crank –config https//raw.githubusercontent.com/aspnet/Benchmarks/main/scenarios/goldilocks.benchmarks.yml –config https//raw.githubusercontent.com/aspnet/Benchmarks/main/build/ci.profile.yml –config https//raw.githubusercontent.com/aspnet/Benchmarks/main/scenarios/steadystate.profile.yml –scenario basicminimalapipublishaot –profile intel-win-app –profile intel-lin-load –application.framework net8.0 –application.options.collectCounters true We get ~67ms startup time, 56MB working set, and ~681k RPS. That’s ~77% faster startup speed, ~87% lower working set, and ~12% lower RPS. The startup speed is expected because the app has already been optimized, and there is no JIT running to start optimizing code. Also, in non-Native AOT apps, because startup methods are likely only called once, tiered compilation will never run on the startup methods so they won’t be as optimized as they could be, but in NativeAOT the startup method will be fully optimized. The working set is a bit surprising, it is lower because Native AOT apps by default run with the new Dynamic Adaptation To Application Sizes (DATAS) GC. This GC setting tries to maintain a balance between throughput and overall memory usage, which we can see it doing with an ~87% lower working set at the cost of some RPS. You can read more about the new GC setting in Maoni0’s blog. Let’s also compare the Native AOT vs. non-Native AOT apps with the Server GC. So we’ll add --application.environmentVariables DOTNET_GCDynamicAdaptationMode=0 when running the Native AOT app. This time we get ~64ms startup time, 403MB working set, and ~730k RPS. The startup time is still extremely fast because changing the GC doesn’t affect that, our working set is closer to the non-Native AOT app but smaller due in part to not having the JIT compiler loaded and running, and our RPS is closer to the non-Native AOT app because we’re using the Server GC which optimizes throughput more than memory usage. AOT GC Startup Working Set RPS false Server 293ms 444MB 762k false DATAS 303ms 77MB 739k true Server 64ms 403MB 730k true DATAS 67ms 56MB 681k Non-Native AOT apps have the JIT optimizing code while it’s running, and starting in .NET 8 the JIT by default will make use of dynamic PGO, this is a really cool feature that Native AOT isn’t able to benefit from and is one reason non-Native AOT apps can have more throughput than Native AOT apps. You can read more about dynamic PGO in the .NET 8 performance blog. If you’re willing to trade some publish size for potentially more optimized code you can pass /pOptimizationPreference=Speed when building and publishing your Native AOT app. When we do this for our benchmark app (with Server GC) we get a publish size of 9.5MB instead of 8.9MB and 745k RPS instead of 730k. The app we’ve been using makes use of Minimal APIs which by default isn’t trim friendly. It does a lot of reflection and dynamic code generation that isn’t statically analyzable so the trimmer isn’t able to safely trim the app. So why don’t we see warnings when we Native AOT publish this app? Because we wrote a source-generator called Request Delegate Generator (RDG) that replaces your MapGet, MapPost, etc. methods with trim friendly code. This source-generator is automatically used for ASP.NET Core apps when trimming/aot publishing. Which leads us into the next section where we dive into RDG. Request Delegate Generator The Request Delegate Generator (RDG) is a source-generator created to make Minimal APIs trimmer and Native AOT friendly. Without RDG, using Minimal APIs will result in many warnings and your app likely won’t work as expected. Here is a quick example to show an endpoint that will result in an exception when using Native AOT without RDG but will work with RDG enabled (or when not using Native AOT). app.MapGet("/test", (Bindable b) => "Hello world!"); public class Bindable { public static ValueTask<Bindable?> BindAsync(HttpContext context, ParameterInfo parameter) { return new ValueTask<Bindable?>(new Bindable()); } } This app throws when you send a GET request to /test because the Bindable.BindAsync method is referenced via reflection and so the trimmer can’t statically figure out that the method is being used and will remove it. Minimal APIs then sees the MapGet call as needing a request body which isn’t allowed by default for GET calls. Besides fixings warnings and making the app work as expected in Native AOT, we get improved first response time and reduced publish size. Without RDG, the first time a request is made to the app is when all the expression trees are generated for all endpoints in the application. Because RDG generates the source for an endpoint at compile time, there is no expression tree generation needed, the code for a specific endpoint is already available and can execute immediately. If we take the app used earlier for benchmarking AOT and look at time to first request we get ~187ms when not running as AOT and without RDG. We then get ~130ms when we enable RDG. When publishing as AOT, the time to first request is ~60ms regardless of using RDG. But this app only has 2 endpoints, so let’s add 1000 more endpoints and see the difference! 2 Routes AOT RDG First Request Publish Size false false 187ms 97MB false true 130ms 97MB true false 60ms 11.15MB true true 60ms 8.89MB 1002 Routes AOT RDG First Request Publish Size false false 1082ms 97MB false true 176ms 97MB true false 157ms 11.15MB true true 84ms 8.89MB Runtime APIs In this section we’ll be looking at changes that mainly involve updating to use new APIs introduced in .NET 8 in the Base Class Library (BCL). SearchValues dotnet/aspnetcore#45300 by @gfoidl, dotnet/aspnetcore#47459, dotnet/aspnetcore#49114, and dotnet/aspnetcore#49117 all make use of the new SearchValues type which lets these code paths take advantage of optimized search implementations for the specific values being searched for. The SearchValues section of the .NET 8 performance blog explains more details about the different search algorithms used and why this type is so cool! Spans dotnet/aspnetcore#46098 makes use of the new MemoryExtensions.Split(ReadOnlySpan<char> source, Span<Range> destination, char separator) method. This allows certain cases of string.Split(...) to be replaced with a non-allocating version. This saves the string[] allocation as well as the individual string allocations for the items in the string[]. More details on this new API can be seen in the .NET 8 Performance post span section. FrozenDictionary Another new type introduced is FrozenDictionary. This allows constructing a dictionary optimized for read operations at the cost of slower construction. dotnet/aspnetcore#49714 switches a Dictionary in routing to use FrozenDictionary. This dictionary is used when routing an http request to the appropriate endpoint which is almost every request to an application. The following tables show the cost of creating the dictionary vs. frozen dictionary, and then the cost of using a dictionary vs. frozen dictionary respectively. You can see that constructing a FrozenDictionary can be up to 13x slower, but the overall time is still in the micro second range (1/1000th of a millisecond) and the FrozenDictionary is only constructed once for the app. What we all like to see is that the per operation performance of using FrozenDictionary is 2.5x-3.5x faster than a Dictionary! [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] public class JumpTableMultipleEntryBenchmark { private string[] _strings; private int[] _segments; private JumpTable _dictionary; private JumpTable _frozenDictionary; private List<(string text, int _)> _entries; [Params(1000)] public int NumRoutes; [GlobalSetup] public void Setup() { _strings = GetStrings(1000); _segments = new int[1000]; for (var i = 0; i < _strings.Length; i++) { _segments[i] = _strings[i].Length; } var samples = new int[NumRoutes]; for (var i = 0; i < samples.Length; i++) { samples[i] = i * (_strings.Length / NumRoutes); } _entries = new List<(string text, int _)>(); for (var i = 0; i < samples.Length; i++) { _entries.Add((_strings[samples[i]], i)); } _dictionary = new DictionaryJumpTable(0, -1, _entries.ToArray()); _frozenDictionary = new FrozenDictionaryJumpTable(0, -1, _entries.ToArray()); } [BenchmarkCategory("GetDestination"), Benchmark(Baseline = true, OperationsPerInvoke = 1000)] public int Dictionary() { var strings = _strings; var segments = _segments; var destination = 0; for (var i = 0; i < strings.Length; i++) { destination = _dictionary.GetDestination(strings[i], segments[i]); } return destination; } [BenchmarkCategory("GetDestination"), Benchmark(OperationsPerInvoke = 1000)] public int FrozenDictionary() { var strings = _strings; var segments = _segments; var destination = 0; for (var i = 0; i < strings.Length; i++) { destination = _frozenDictionary.GetDestination(strings[i], segments[i]); } return destination; } [BenchmarkCategory("Create"), Benchmark(Baseline = true)] public JumpTable CreateDictionaryJumpTable() => new DictionaryJumpTable(0, -1, _entries.ToArray()); [BenchmarkCategory("Create"), Benchmark] public JumpTable CreateFrozenDictionaryJumpTable() => new FrozenDictionaryJumpTable(0, -1, _entries.ToArray()); private static string[] GetStrings(int count) { var strings = new string[count]; for (var i = 0; i < count; i++) { var guid = Guid.NewGuid().ToString(); // Between 5 and 36 characters var text = guid.Substring(0, Math.Max(5, Math.Min(i, 36))); if (char.IsDigit(text[0])) { // Convert first character to a letter. text = ((char)(text[0] + ('G' - '0'))) + text.Substring(1); } if (i % 2 == 0) { // Lowercase half of them text = text.ToLowerInvariant(); } strings[i] = text; } return strings; } } public abstract class JumpTable { public abstract int GetDestination(string path, int segmentLength); } internal sealed class DictionaryJumpTable JumpTable { private readonly int _defaultDestination; private readonly int _exitDestination; private readonly Dictionary<string, int> _dictionary; public DictionaryJumpTable( int defaultDestination, int exitDestination, (string text, int destination)[] entries) { _defaultDestination = defaultDestination; _exitDestination = exitDestination; _dictionary = entries.ToDictionary(e => e.text, e => e.destination, StringComparer.OrdinalIgnoreCase); } public override int GetDestination(string path, int segmentLength) { if (segmentLength == 0) { return _exitDestination; } var text = path.Substring(0, segmentLength); if (_dictionary.TryGetValue(text, out var destination)) { return destination; } return _defaultDestination; } } internal sealed class FrozenDictionaryJumpTable JumpTable { private readonly int _defaultDestination; private readonly int _exitDestination; private readonly FrozenDictionary<string, int> _dictionary; public FrozenDictionaryJumpTable( int defaultDestination, int exitDestination, (string text, int destination)[] entries) { _defaultDestination = defaultDestination; _exitDestination = exitDestination; _dictionary = entries.ToFrozenDictionary(e => e.text, e => e.destination, StringComparer.OrdinalIgnoreCase); } public override int GetDestination(string path, int segmentLength) { if (segmentLength == 0) { return _exitDestination; } var text = path.Substring(0, segmentLength); if (_dictionary.TryGetValue(text, out var destination)) { return destination; } return _defaultDestination; } } Method NumRoutes Mean Error StdDev Ratio RatioSD CreateDictionaryJumpTable 25 735.797 ns 8.5503 ns 7.5797 ns 1.00 0.00 CreateFrozenDictionaryJumpTable 25 4,677.927 ns 80.4279 ns 71.2972 ns 6.36 0.11 CreateDictionaryJumpTable 50 1,433.309 ns 19.4435 ns 17.2362 ns 1.00 0.00 CreateFrozenDictionaryJumpTable 50 10,065.905 ns 188.7031 ns 176.5130 ns 7.03 0.12 CreateDictionaryJumpTable 100 2,712.224 ns 46.0878 ns 53.0747 ns 1.00 0.00 CreateFrozenDictionaryJumpTable 100 28,397.809 ns 358.2159 ns 335.0754 ns 10.46 0.20 CreateDictionaryJumpTable 1000 28,279.153 ns 424.3761 ns 354.3733 ns 1.00 0.00 CreateFrozenDictionaryJumpTable 1000 313,515.684 ns 6,148.5162 ns 8,208.0925 ns 11.26 0.33 Dictionary 25 21.428 ns 0.1816 ns 0.1516 ns 1.00 0.00 FrozenDictionary 25 7.137 ns 0.0588 ns 0.0521 ns 0.33 0.00 Dictionary 50 21.630 ns 0.1978 ns 0.1851 ns 1.00 0.00 FrozenDictionary 50 7.476 ns 0.0874 ns 0.0818 ns 0.35 0.00 Dictionary 100 23.508 ns 0.3498 ns 0.3272 ns 1.00 0.00 FrozenDictionary 100 7.123 ns 0.0840 ns 0.0745 ns 0.30 0.00 Dictionary 1000 23.761 ns 0.2360 ns 0.2207 ns 1.00 0.00 FrozenDictionary 1000 8.516 ns 0.1508 ns 0.1337 ns 0.36 0.01 Other This section is a compilation of changes that enhance performance but do not fall under any of the preceding categories. Regex As part of the AOT effort, we noticed the regex created in RegexRouteConstraint (see route constraints for more info) was adding ~1MB to the published app size. This is because the route constraints are dynamic (application code defines them) and we were using the Regex constructor that accepts RegexOptions. This meant the trimmer has to keep around all regex code that could potentially be used, including the NonBacktracking engine which keeps ~.8MB of code. By adding RegexOptions.Compiled the trimmer can now see that the NonBacktracking code will not be used and it can reduce the application size by ~.8MB. Additionally, using compiled regexes is faster than using the interpreted regex. The quick fix was to just add RegexOptions.Compiled when creating the Regex which was done in dotnet/aspnetcore#46192 by @eugeneogongo. The problem is that this slows down app startup because we resolve constraints when starting the app and compiled regexes are slower to construct. dotnet/aspnetcore#46323 fixes this by lazily initializing the regexes so app startup is actually faster than 7.0 when we weren’t using compiled regexes. It also added caching to the route constraints which means if you share constraints in multiple routes you will save allocations by sharing constraints across routes. Running a microbenchmark for the route builder to measure startup performance shows an almost 450% improvement when using 1000 routes due to no longer initializing the regexes. The benchmark lives in the dotnet/aspnetcore repo. It has a lot of setup code and would be a bit too long to put in this post. Before with interpreted regexes Method Mean Op/s Gen 0 Gen 1 Allocated Build 6.739 ms 148.4 15.6250 – 7 MB After with compiled and lazy regexes Method Mean Op/s Gen 0 Gen 1 Allocated Build 1.521 ms 657.2 5.8594 1.9531 2 MB Another Regex improvement came from dotnet/aspnetcore#44770 which switched a Regex usage in routing to use the Regex Source Generator. This moves the cost of compiling the Regex to build time, as well as resulting in faster Regex code due to optimizations the source generator takes advantage of that the in-process Regex compiler does not. We’ll show a simplified example that demonstrates using the generated regex vs. the compiled regex. public partial class AlphaRegex { static Regex Net7Constraint = new Regex( @"^[a-z]*$", RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, TimeSpan.FromSeconds(10)); static Regex Net8Constraint = GetAlphaRouteRegex(); [GeneratedRegex(@"^[A-Za-z]*$")] private static partial Regex GetAlphaRouteRegex(); [Benchmark(Baseline = true)] public bool CompiledRegex() { return Net7Constraint.IsMatch("Administration") && Net7Constraint.IsMatch("US"); } [Benchmark] public bool SourceGenRegex() { return Net8Constraint.IsMatch("Administration") && Net8Constraint.IsMatch("US"); } } Method Mean Error StdDev Ratio CompiledRegex 86.92 ns 0.572 ns 0.447 ns 1.00 SourceGenRegex 57.81 ns 0.860 ns 0.805 ns 0.66 Analyzers Analyzers are useful for pointing out issues in code that can be hard to convey in API signatures, suggesting code patterns that are more readable, and they can also suggest more performant ways to write code. dotnet/aspnetcore#44799 and dotnet/aspnetcore#44791 both from @martincostello enabled CA1854 which helps avoid 2 dictionary lookups when only 1 is needed, and dotnet/aspnetcore#44269 enables a bunch of analyzers many of which help use more performant APIs and are described in more detail in last years .NET 7 Performance Post. I would encourage developers who are interested in performance in their own products to checkout performance focused analyzers which contains a list of many analyzers that will help avoid easy to fix performance issues. StringBuilder StringBuilder is an extremely useful class for constructing a string when you either can’t precompute the size of the string to create or want an easy way to construct a string without the complications involved with using string.Create(...). StringBuilder comes with a lot of helpful methods as well as a custom implementation of an InterpolatedStringHandler. What this means is that you can “create” strings to add to the StringBuilder without actually allocating the string. For example, previously you might have written stringBuilder.Append(FormattableString.Invariant($"{key} = {value}"));. This would have allocated a string via FormattableString.Invariant(...) then put it in the StringBuilders internal char[] buffer, making the string a temporary allocation. Instead you can write stringBuilder.Append(CultureInfo.InvariantCulture, $"{key} = {value}");. This also looks like it would allocate a string via $"{key} = {value}", but because StringBuilder has a custom InterpolatedStringHandler the string isn’t actually allocated and instead is written directly to the internal char[]. dotnet/aspnetcore#44691 fixes some usage patterns with StringBuilder to avoid allocations as well as makes use of the InterpolatedStringHandler overload(s). One specific example was taking a byte[] and converting it into a string in hexidecimal format so we could send it as a query string. [MemoryDiagnoser] public class AppendBenchmark { private byte[] _b = new byte[30]; [GlobalSetup] public void Setup() { RandomNumberGenerator.Fill(_b); } [Benchmark] public string AppendToString() { var sb = new StringBuilder(); foreach (var b in _b) { sb.Append(b.ToString("x2", CultureInfo.InvariantCulture)); } return sb.ToString(); } [Benchmark] public string AppendInterpolated() { var sb = new StringBuilder(); foreach (var b in _b) { sb.Append(CultureInfo.InvariantCulture, $"{bx2}"); } return sb.ToString(); } } Method Mean Gen0 Allocated AppendToString 748.7 ns 0.1841 1448 B AppendInterpolated 739.7 ns 0.0620 488 B Summary Thanks for reading! Try out .NET 8 and let us know how your app’s performance has changed! We are always looking for feedback on how to improve the product and look forward to your contributions, be it an issue report or a PR. If you want more performance goodness, you can read the Performance Improvements in .NET 8 post. Also, take a look at Developer Stories which showcases multiple teams at Microsoft migrating from .NET Framework to .NET or to newer versions of .NET and seeing major performance and operating cost wins. The post Performance Improvements in ASP.NET Core 8 appeared first on .NET Blog.


Understanding ASP.Net Core 2.2 Database Context C ...
Category: .Net 7

When working in asp.net core 2.2, you will come across the class in the Model folder called Datab ...


Views: 418 Likes: 86
Docker on Raspberry Pi Error .Net Core 3.1 Error: ...
Category: Docker

How do you resolve this error Docker on Raspberry Pi Error .Net Core 3.1 Error ...


Views: 924 Likes: 119
 The .NET Stacks #18: RC1 is here, the fate of .NET Standard, and F# with Isaac Abraham
The .NET Stacks #18 RC1 is here, the fate of .NE ...

.NET 5 RC1 is hereThis week, Microsoft pushed out the RC1 release for .NET 5, which is scheduled to officially “go live” in early November. RC1 comes with a “go live” license, which means you get production support for it. With that, RC1 versions were released for ASP.NET Core and EF Core as well.I’ve dug deep on a variety of new features in the last few months or so—I won’t  rehash them here. However, the links are worth checking out. For example, Richard Lander goes in-depth on C# 9 records and System.Text.Json.The fate of .NET StandardWhile there are many great updates to the upcoming .NET 5 release, a big selling point is at a higher level the promise of a unified SDK experience for all of .NET. The idea is that you’ll be able to use one platform regardless of your needs—whether it’s Windows, Linux, macOS, Android, WebAssembly, and more. (Because of internal resourcing constraints, Xamarin will join the party in 2021, with .NET 6.)Microsoft has definitely struggled in communicating a clear direction for .NET the last several years, so when you pair a unified experience with predictable releases and roadmaps, it’s music to our ears.You’ve probably wondered what does this mean for .NET Standard? The unified experience is great, but what about when you have .NET Framework apps to support? (If you’re new to .NET Standard, it’s more-or-less a specification where you can target a version of Standard, and all .NET implementations that target it are guaranteed to support all its .NET APIs.)Immo Landwerth shed some light on the subject this week. .NET Standard is being thrown to the .NET purgatory with .NET Framework it’ll still technically be around, and .NET 5 will support it—but the current version, 2.1, will be its last.As a result, we have some new target framework names net5.0, for apps that run anywhere, combines and replaces netcoreapp and netstandard. There’s also net5.0-windows (with Android and iOS flavors to come) for Windows-specific use cases, like UWP.OK, so .NET Standard is still around but we have new target framework names. What should you do? With .NET Standard 2.0 being the last version to support .NET Framework, use netstandard2.0 for code sharing between .NET Framework and other platforms. You can use netstandard2.1 to share between Mono, Xamarin, and .NET Core 3.x, and then net5.0 for anything else (and especially when you want to use .NET 5 improvements and new language features). You’ll definitely want to check out the post for all the details.What a mess .NET Standard promised API uniformity and now we’re even having to choose between that and a new way of doing things. The post lays out why .NET Standard is problematic, and it makes sense. But when you’re trying to innovate at a feverish pace but still support customers on .NET Framework, the cost is complexity—and the irony is that with uniformity with .NET 5, that won’t apply when you have legacy apps to support.Dev Discussions Isaac AbrahamAs much as we all love C#, there’s something that needs reminding from time to time C# is not .NET. It is a large and important part of .NET, for sure, but .NET also supports two other languages Visual Basic and F#. As for F#, it’s been gaining quite a bit of popularity over the last several years, and for good reason it’s approachable, concise, and allows you to embrace a functional-first language while leveraging the power of the .NET ecosystem.I caught up with Isaac Abraham to learn more about F#. After spending a decade as a C# developer, Isaac embraced the power of F# and founded Compositional IT, a functional-first consultancy. He’s also the author of Get Programming with F# A Guide for .NET Developers.I know it’s more nuanced than this but if you could sell F# to C# developers in a sentence or two, how would you do it?F# really does bring the fun back into software development. You’ll feel more productive, more confident and more empowered to deliver high-quality software for your customers.Functional programming is getting a lot of attention in the C# world, as the language is adopting much of its concepts (especially with C# 9). It’s a weird balance trying to have functional concepts in an OO language. How do you feel the balance is going?I have mixed opinions on this. On the one hand, for the C# dev it’s great—they have a more powerful toolkit at their disposal. But I would hate to be a new developer starting in C# for the first time. There are so many ways to do things now, and the feature (and custom operator!) count is going through the roof. More than that, I worry that we’ll end up with a kind of bifurcated C# ecosystem—those that adopt the new features and those that won’t, and worse still the risk of losing the identity of what C# really is.I’m interested to see how it works out. Introducing things like records into C# is going to lead to some new and different design patterns being used that will have to naturally evolve over time.I won’t ask if C# will replace F#—you’ve eloquently written about why the answer is no. I will ask you this, though is there a dividing line of when you should use C# (OO with functional concepts) or straight to F#?I’m not really sure the idea of “OO with functional concepts” really gels, to be honest. Some of the core ideas of FP—immutability and expressions—are kind of the opposite of OO, which is all centered around mutable data structures, statements and side effects. By all means use the features C# provides that come from the FP world and use them where it helps—LINQ, higher order functions, pattern matching, immutable data structures—but the more you try out those features to try what they can do without using OO constructs, the more you’ll find C# pulls you “back.” It’s a little like driving an Audi on the German motorway but never getting out of third gear.My view is that 80% of the C# population today—maybe more—would be more productive and happier in F#. If you’re using LINQ, you favour composition over inheritance, and you’re excited by some of the new features in C# like records, switch expressions, tuples, and so on, F# will probably be a natural fit for you. All of those features are optimised as first-class citizens of the language, whilst things like mutability and classes are possible, but are somewhat atypical.This also feeds back to your other question—I do fear that people will try these features out within the context of OO patterns, find them somehow limited, and leave thinking that FP isn’t worthwhile.Let’s say I’m a C# programmer and want to get into F#. Is there any C# knowledge that will help me understand the concepts, or is it best to clear my mind of any preconceived notions before learning?Probably the closest concept would be to imagine your whole program was a single LINQ query. Or, from a web app—imagine every controller method was a LINQ query. In reality it’s not like that, but that’s the closest I can think of. The fact that you’ll know .NET inside and out is also a massive help. The things to forget are basically the OO and imperative parts of the language classes, inheritance, mutable variables, while loops, and statements. You don’t really use any of those in everyday F# (and believe me, you don’t need any of them to write standard line of business apps).As an OO programmer, it’s so painful always having to worry about “the billion dollar mistake” nulls. We can’t assume anything since we’re mutating objects all over the place and often throw up our hands and do null checks everywhere (although the language has improved in the last few versions). How does F# handle nulls? Is it less painful?For F# types that you create, the language simply says null isn’t allowed, and there’s no such thing as null. So in a sense, the problem goes away by simply removing it from the type system. Of course, you still have to handle business cases of “absence of a value,” so you create optional values—basically a value that can either have something or nothing. The compiler won’t let you access the “something” unless you first “check” that the value isn’t nothing.So, you spend more time upfront thinking about how you model your domain rather than simply saying that everything and anything is nullable. The good thing is, you totally lose that fear of “can this value be null when I dot into it” because it’s simply not part of the type system. It’s kind of like the flow analysis that C# 8 introduced for nullability checks—but instead of flow analysis, it’s much simpler. It’s just a built-in type in the language. There’s nothing magical about it.However, when it comes to interoperating with C# (and therefore the whole BCL), F# doesn’t have any special compiler support for null checks, so developers will often create a kind of “anti-corruption” layer between the “unsafe outside world” and the safe F# layer, which simply doesn’t have nulls. There’s also work going on to bring in support for the nullability surface in the BCL but I suspect that this will be in F# 6.F#, and functional programming in general, emphasizes purity no side effects. Does F# enforce this, or is it just designed with it in mind?No, it doesn’t enforce it. There’s some parts of the language which make it obvious when you’re doing a side effect, but it’s nothing like what Haskell does. For starters, the CLR and BCL don’t have any notion of a side effect, so I think that this would difficult to introduce. It’s a good example of some of the design decisions that F# took when running on .NET—you get all the goodness of .NET and the ecosystem, but some things like this would be challenging to do. In fact, F# has a lot of escape hatches like this. It strongly guides you down a certain path, but it usually has ways that you can do your own thing if you really need to.You still can (and people do) write entire systems that are functionally pure, and the benefits of pure functions are certainly something that most F# folks are aware of (it’s much easier to reason about and test, for example). It just means that the language won’t force you to do it.What is your one piece of programming advice?Great question. I think one thing I try to keep in mind is to avoid premature optimisation and design. Design systems for what you know is going to be needed, with extension points for what will most likely be required. You can never design for every eventuality, and you’ll sometimes get it wrong, that’s life—optimise for what is the most likely outcome.To read the entire interview, head on over to my site.?? Last week in the .NET world?? The Top 3.NET 5 RC 1 is out Richard Lander has the announcement, Jeremy Likness talks about EF updates, and Daniel Roth discusses what’s new for ASP.NET.Immo Landwerth speaks about the future of .NET Standard.Steve Gordon walks through performance optimizations.?? AnnouncementsThere’s a new Learn module for deploying a cloud-native ASP.NET microservice with GitHub Actions.Mark Downie talks about disassembly improvements for optimized managed debugging.Microsoft Edge announces source order viewer in their DevTools.Tara Overfield provides September cumulative updates for the .NET Framework.?? Community and eventsMicrosoft Ignite occurs this Tuesday through Thursday.The .NET Docs Show talks about the dot.net site with Maíra Wenzel.Three .NET community standups this week .NET Tooling finds latent bugs in .NET 5, Entity Framework talks EF Core 5 migrations, and ASP.NET discusses new features for .NET API developers.?? ASP .NET / BlazorShaun Curtis launches a series on building a database application in Blazor.Patrick Smacchia walks through the architecture of a C# game rendered with Blazor, Xamarin, UWP, WPF, and Winforms.David Ramel writes about increased Blazor performance in .NET 5 RC1.Rick Strahl warns about missing await calls for async code in ASP.NET Code middleware.Dominique St-Amand secures an ASP.NET Core Web API with an API key.Vladimir Pecanac discusses how to secure sensitive data locally with ASP.NET Core.David Grace explores why you app might not be working in IIS.?? .NET CoreKay Ewbank discusses the latent bug discovery feature coming with .NET 5.Michal Bialecki executes raw SQL with EF 5.Fredrik Rudberg serves images stored in a database through static URLs using .NET Core 3.1.Shawn Wildermuth talks about hosting Vue in .NET Core.? The cloudVladimir Pecanac configures the Azure Key Vault in ASP.NET Core.Richard Seroter compares the CLI experience between Azure, AWS, and GCP.Jon Gallant walks though the September updates to the Azure SDKs.Christopher Scott introduces the new Azure Tables client libraries.Daniel Krzyczkowski extracts Excel file content with Azure Logic Apps and Azure Functions.Kevin Griffin touts the great performance for Azure Static Web Apps and Azure Functions.Matt Small finds a gotcha you can’t use an Azure Key Vault firewall if you’re in a situation where you’re using App Gateway along with a Key Vault certificate for SSL termination.Gunnar Peipman hosts applications on Azure B-series virtual machines.?? C#Jeremy Clark shows how to see all the exceptions when calling “await Task.WhenAll.”.Jerome Laban uses MSBuild items and properties in C# 9 source generators.?? F#A nice rundown of 10 ways to try F# in the browser.Daniel Bykat talks about the PORK framework and its use with F#.Alican Demirtas discusses string interpolation in F#.Paul Biggar talks about his async adventures.?? ToolsDerek Comartin does a review of MediatR.Tom Deseyn uses OpenAPI with .NET Core.John Juback builds cross-platform desktop apps with Electron.NET.Andrew Lock continues his k8s series by deploying applications with Helm.You can now debug Linux core dumps on the Windows Subsystem for Linux (WSL) or a remote Linux system directly from Visual Studio.Adam Storr uses Project Tye to run .NET worker services.?? XamarinJoe Meyer wires up a fullscreen video background.Khalid Abuhakmeh animates a mic drop.Denys Fiediaiev uses MvvmCross to log with Xamarin.?? PodcastsThe .NET Rocks podcast talks about ML with Zoiner Tejada.Software Engineering Radio talks with Philip Kiely about writing for software developers.The Merge Conflict podcast discusses the new Half type.The Coding Blocks podcast asks is Kubernetes programming?The Azure DevOps Podcast talks with Steve Sanderson about Blazor.?? VideosThe ON .NET Show talks about Steeltoe configuration.Azure Friday talks about Azure landing zones.Scott Hanselman gives us a primer on the cloud.The ASP.NET Monsters send dates from JavaScript to .NET.


dotnet 8 not running in development mode
Category: .Net 7

Question How do you make dotnet 8 run in development mode when you run it from the command prom ...


Views: 0 Likes: 5
MSB1009: Docker File Error when building Asp.Net 5
Category: .Net 7

The most common Error when building a Docker File for Asp.Net Cor ...


Views: 586 Likes: 67
error : MSB4803: The task "ResolveComReference" is ...
Category: .Net 7

How do I resolve this error? "C\Program Files\d ...


Views: 0 Likes: 61
Performance Tuning for ASP.NET Web Applications
Category: .Net 7

Performance Tuning in ASP.NET Core with C# ...


Views: 398 Likes: 109
DotNet Software Development and Performance Tools
Category: .Net 7

[11/11/2022] Bombardia Web Stress Testing Tools<a h ...


Views: 0 Likes: 75
[Resolved] Dot Net Core Error "Project file is inc ...
Category: .Net 7

Sometimes when working with .Net Core 2.2 project, you might end up with this error Project file ...


Views: 2649 Likes: 129
ASP.Net Core 2.2 Not Required Field in Data Model. ...
Category: .Net 7

Question How can I make a Field or Class property in a POCO Data Model not required or Optional ...


Views: 812 Likes: 59
.NET 8 Performance Improvements in .NET MAUI
.NET 8 Performance Improvements in .NET MAUI

The major focus for .NET MAUI in the .NET 8 release is quality. As such, alot of our focus has been fixing bugs instead of chasing lofty performance goals. In .NET 8, we merged 1,559 pull requests that closed 596 total issues. These include changes from the .NET MAUI team as well as the .NET MAUI community. We are optimistic that this should result in a significant increase in quality in .NET 8. However! We still have plenty of performance changes to showcase. Building upon the fundamental performance improvements in .NET 8 we discover “low-hanging” fruit constantly, and there were high-voted performance issues on GitHub we tried to tackle. Our goal is to continue to make .NET MAUI faster in each release, read on for details! For a review of the performance improvements in past releases, see our posts for .NET 6 and 7. This also gives you an idea of the improvements you would see migrating from Xamarin.Forms to .NET MAUI .NET 7 Performance Improvements in .NET MAUI .NET 6 Performance Improvements in .NET MAUI Table Of Contents New features AndroidStripILAfterAOT AndroidEnableMarshalMethods NativeAOT on iOS Build & Inner Loop Performance Filter Android ps -A output with grep Port WindowsAppSDK usage of vcmeta.dll to C# Improvements to remote iOS builds on Windows Improvements to Android inner-loop XAML Compilation no longer uses LoadInSeparateAppDomain Performance or App Size Improvements Structs and IEquatable in .NET MAUI Fix performance issue in {AppThemeBinding} Address CA1307 and CA1309 for performance Address CA1311 for performance Remove unused ViewAttachedToWindow event on Android Remove unneeded System.Reflection for {Binding} Use StringComparer.Ordinal for Dictionary and HashSet Reduce Java interop in MauiDrawable on Android Improve layout performance of Label on Android Reduce Java interop calls for controls in .NET MAUI Improve performance of Entry.MaxLength on Android Improve memory usage of CollectionView on Windows Use UnmanagedCallersOnlyAttribute on Apple platforms Faster Java interop for strings on Android Faster Java interop for C# events on Android Use Function Pointers for JNI Removed Xamarin.AndroidX.Legacy.Support.V4 Deduplication of generics on iOS and macOS Fix System.Linq.Expressions implementation on iOS-like platforms Set DynamicCodeSupport=false for iOS and Catalyst Memory Leaks Memory Leaks and Quality Diagnosing leaks in .NET MAUI Patterns that cause leaks C# events Circular references on Apple platforms Roslyn analyzer for Apple platforms Tooling and Documentation Simplified dotnet-trace and dotnet-dsrouter dotnet-gcdump Support for Mobile New Features AndroidStripILAfterAOT Once Upon A Time we had a brilliant thought if AOT pre-compiles C# methods, do we need the managed method anymore? Removing the C# method body would allow assemblies to be smaller. .NET iOS applications already do this, so why not Android as well? While the idea is straightforward, implementation was not iOS uses “Full” AOT, which AOT’s all methods into a form that doesn’t require a runtime JIT. This allowed iOS to run cil-strip, removing all method bodies from all managed types. At the time, Xamarin.Android only supported “normal” AOT, and normal AOT requires a JIT for certain constructs such as generic types and generic methods. This meant that attempting to run cil-strip would result in runtime errors if a method body was removed that was actually required at runtime. This was particularly bad because cil-strip could only remove all method bodies! We are re-intoducing IL stripping for .NET 8. Add a new $(AndroidStripILAfterAOT) MSBuild property. When true, the <MonoAOTCompiler/> task will track which method bodies were actually AOT’d, storing this information into %(_MonoAOTCompiledAssemblies.MethodTokenFile), and the new <ILStrip/> task will update the input assemblies, removing all method bodies that can be removed. By default enabling $(AndroidStripILAfterAOT) will override the default $(AndroidEnableProfiledAot) setting, allowing all trimmable AOT’d methods to be removed. This choice was made because $(AndroidStripILAfterAOT) is most useful when AOT-compiling your entire application. Profiled AOT and IL stripping can be used together by explicitly setting both within the .csproj, but with the only benefit being a small .apk size improvement <PropertyGroup Condition=" '$(Configuration)' == 'Release' "> <AndroidStripILAfterAOT>true</AndroidStripILAfterAOT> <AndroidEnableProfiledAot>true</AndroidEnableProfiledAot> </PropertyGroup> .apk size results for a dotnet new android app $(AndroidStripILAfterAOT) $(AndroidEnableProfiledAot) .apk size true true 7.7MB true false 8.1MB false true 7.7MB false false 8.4MB Note that AndroidStripILAfterAOT=false and AndroidEnableProfiledAot=true is the default Release configuration environment, for 7.7MB. A project that only sets AndroidStripILAfterAOT=true implicitly sets AndroidEnableProfiledAot=false, resulting in an 8.1MB app. See xamarin-android#8172 and dotnet/runtime#86722 for details about this feature. AndroidEnableMarshalMethods .NET 8 introduces a new experimental setting for Release configurations <PropertyGroup Condition=" '$(Configuration)' == 'Release' "> <AndroidEnableMarshalMethods>true</AndroidEnableMarshalMethods> <!-- Note that single-architecture apps will be most successful --> <RuntimeIdentifier>android-arm64</RuntimeIdentifier> </PropertyGroup> We hope to enable this feature by default in .NET 9, but for now we are providing the setting as an opt-in, experimental feature. Applications that only target one architecture, such as RuntimeIdentifier=android-arm64, will likely be able to enable this feature without issue. Background on Marshal Methods A JNI marshal method is a JNI-callable function pointer provided to JNIEnvRegisterNatives(). Currently, JNI marshal methods are provided via the interaction between code we generate and JNINativeWrapper.CreateDelegate() Our code-generator emits the “actual” JNI-callable method. JNINativeWrapper.CreateDelegate() uses System.Reflection.Emit to wrap the method for exception marshaling. JNI marshal methods are needed for all Java-to-C# transitions. Consider the virtual Activity.OnCreate() method partial class Activity { static Delegate? cb_onCreate_Landroid_os_Bundle_; static Delegate GetOnCreate_Landroid_os_Bundle_Handler () { if (cb_onCreate_Landroid_os_Bundle_ == null) cb_onCreate_Landroid_os_Bundle_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_V) n_OnCreate_Landroid_os_Bundle_); return cb_onCreate_Landroid_os_Bundle_; } static void n_OnCreate_Landroid_os_Bundle_ (IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState) { var __this = globalJava.Lang.Object.GetObject<Android.App.Activity> (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; var savedInstanceState = globalJava.Lang.Object.GetObject<Android.OS.Bundle> (native_savedInstanceState, JniHandleOwnership.DoNotTransfer); __this.OnCreate (savedInstanceState); } // Metadata.xml XPath method reference path="/api/package[@name='android.app']/class[@name='Activity']/method[@name='onCreate' and count(parameter)=1 and parameter[1][@type='android.os.Bundle']]" [Register ("onCreate", "(Landroid/os/Bundle;)V", "GetOnCreate_Landroid_os_Bundle_Handler")] protected virtual unsafe void OnCreate (Android.OS.Bundle? savedInstanceState) => ... } Activity.n_OnCreate_Landroid_os_Bundle_() is the JNI marshal method, responsible for marshaling parameters from JNI values into C# types, forwarding the method invocation to Activity.OnCreate(), and (if necessary) marshaling the return value back to JNI. Activity.GetOnCreate_Landroid_os_Bundle_Handler() is part of the type registration infrastructure, providing a Delegate instance to RegisterNativeMembers .RegisterNativeMembers(), which is eventually passed to JNIEnvRegisterNatives(). While this works, it’s not incredibly performant unless using one of the optimized delegate types added in xamarin-android#6657, System.Reflection.Emit is used to create a wrapper around the marshal method, which is something we’ve wanted to avoid doing for years. Thus, the idea since we’re already bundling a native toolchain and using LLVM-IR to produce libxamarin-app.so, what if we emitted Java native method names and skipped all the done as part of Runtime.register() and JNIEnv.RegisterJniNatives()? Given class MyActivity Activity { protected override void OnCreate(Bundle? state) => ... } During the build, libxamarin-app.so would contain the function JNIEXPORT void JNICALL Java_crc..._MyActivity_n_1onCreate (JNIEnv *env, jobject self, jobject state); During App runtime, the Runtime.register() invocation present in Java Callable Wrappers would either be omitted or would be a no-op, and Android/JNI would instead resolve MyActivity.n_onCreate() as Java_crc..._MyActivity_n_1onCreate(). We call this effort “LLVM Marshal Methods”, which is currently experimental in .NET 8. Many of the specifics are still being investigated, and this feature will be spread across various areas. See xamarin-android#7351 for details about this experimental feature. NativeAOT on iOS In .NET 7, we started an experiment to see what it would take to support NativeAOT on iOS. Going from prototype to an initial implementation .NET 8 Preview 6 included NativeAOT as an experimental feature for iOS. To opt into NativeAOT in a MAUI iOS project, use the following settings in your project file <PropertyGroup Condition="$([MSBuild]GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios' and '$(Configuration)' == 'Release'"> <!-- PublishAot=true indicates NativeAOT, while omitting this property would use Mono's AOT --> <PublishAot>true</PublishAot> </PropertyGroup> Then to build the application for an iOS device $ dotnet publish -f net8.0-ios -r ios-arm64 MSBuild version 17.8.0+6cdef4241 for .NET ... Build succeeded. 0 Error(s) Note We may consider unifying and improving MSBuild property names for this feature in future .NET releases. To do a one-off build at the command-line you may also need to specify -pPublishAotUsingRuntimePack=true in addition to -pPublishAot=true. One of the main culprits for the first release was how the iOS workload supports Objective-C interoperability. The problem was mainly related to the type registration system which is the key component for efficiently supporting iOS-like platforms (see docs for details). In its implementation, the type registration system depends on type metadata tokens which are not available with NativeAOT. Therefore, in order to leverage the benefits of highly efficient NativeAOT runtime, we had to adapt. dotnet/runtime#80912 includes the discussion around how to tackle this problem, and finally in xamarin-macios#18268 we implemented a new managed static registrar that works with NativeAOT. The new managed static registrar does not just benefit us with being compatible with NativeAOT, but is also much faster than the default one, and is available for all supported runtimes (see docs for details). Along the way, we had a great help from our GH community and their contribution (code reviews, PRs) was essential to helps us move forward quickly and deliver this feature on time. A few from many PR’s that helped and unblocked us on our journey were dotnet/runtime#77956 dotnet/runtime#78280 dotnet/runtime#82317 dotnet/runtime#85996 and the list goes on… As .NET 8 Preview 6 came along, we finally managed to release our first version of the NativeAOT on iOS which also supports MAUI. See the blog post on .NET 8 Preview 6 for details about what we were able to accomplish in the initial release. In subsequent .NET 8 releases, results improved quite a bit, as we were identifying and resolving issues along the way. The graph below shows the .NET MAUI iOS template app size comparison throughout the preview releases We had steady progress and estimated size savings reported, due to fixing the following issues dotnet/runtime#87924 – fixed major NativeAOT size issue with AOT-incompatible code paths in System.Linq.Expressions and also made fully NativeAOT compatible when targeting iOS xamarin-macios#18332 – reduced the size of __LINKEDIT Export Info section in stripped binaries Furthermore, in the latest RC 1 release the app size went even further down reaching -50% smaller apps for the template .NET MAUI iOS applications compared to Mono. Most impactful issues/PRs that contributed to this xamarin-macios#18734 – Make Full the default link mode for NativeAOT xamarin-macios#18584 – Make the codebase trimming compatible through a series of PRs. Even though app size was our primary metric to focus on, for the RC 1 release, we also measured startup time performance comparisons for a .NET MAUI iOS template app comparing NativeAOT and Mono where NativeAOT results with almost 2x faster startup time. Key Takeaways For NativeAOT scenarios on iOS, changing the default link mode to Full (xamarin-macios#18734) is probably the biggest improvement for application size. But at the same time, this change can also break applications which are not fully AOT and trim-compatible. In Full link mode, the trimmer might trim away AOT incompatible code paths (think about reflection usage) which are accessed dynamically at runtime. Full link mode is not the default configuration when using the Mono runtime, so it is possible that some applications are not fully AOT-compatible. Supporting NativeAOT on iOS is an experimental feature and still a work-in-progress, and our plan is to address the potential issues with Full link mode incrementally As a first step, we enabled trim, AOT, and single-file warnings by default in xamarin-macios#18571. The enabled warnings should make our customers aware at build-time, whether a use of a certain framework or a library, or some C# constructs in their code, is incompatible with NativeAOT – and could crash at runtime. This information should guide our customers to write AOT-compatible code, but also to help us improve our frameworks and libraries with the same goal of fully utilising the benefits of AOT compilation. The second step, was clearing up all the warnings coming from Microsoft.iOS and System.Private.CoreLib assemblies reported for a template iOS application with xamarin-macios#18629 and dotnet/runtime#91520. In future releases, we plan to address the warnings coming from the MAUI framework and further improve the overall user-experience. Our goal is to have fully AOT and trim-compatible frameworks. .NET 8 will support targeting iOS platforms with NativeAOT as an opt-in feature and shows great potential by generating up to 50% smaller and 50% faster startup compared to Mono. Considering the great performance that NativeAOT promises, please help us on this journey and try out your applications with NativeAOT and report any potential issues. At the same time, let us know when NativeAOT “just works” out-of-the-box. To follow future progress, see dotnet/runtime#80905. Last but not least, we would like to thank our GH contributors, who are helping us make NativeAOT on iOS possible. Build & Inner Loop Performance Filter Android ps -A output with grep When profiling the Android inner loop for a .NET MAUI project with PerfView we found around 1.2% of CPU time was spent just trying to get the process ID of the running Android application. When changing Tools > Options > Xamarin > Xamarin Diagnostics output verbosity to be Diagnostics, you could see -- Start GetProcessId - 12/02/2022 110557 (96.9929ms) -- [INPUT] ps -A [OUTPUT] USER PID PPID VSZ RSS WCHAN ADDR S NAME root 1 0 10943736 4288 0 0 S init root 2 0 0 0 0 0 S [kthreadd] ... Hundreds of more lines! u0_a993 14500 1340 14910808 250404 0 0 R com.companyname.mauiapp42 -- End GetProcessId -- The Xamarin/.NET MAUI extension in Visual Studio polls every second to see if the application has exited. This is useful for changing the play/stop button state if you force close the app, etc. Testing on a Pixel 5, we could see the command is actually 762 lines of output! > (adb shell ps -A).Count 762 What we could do instead is something like > adb shell "ps -A | grep -w -E 'PID|com.companyname.mauiapp42'" Where we pipe the output of ps -A to the grep command on the Android device. Yes, Android has a subset of unix commands available! We filter on either a line containing PID or your application’s package name. The result is now the IDE is only parsing 4 lines [INPUT] ps -A | grep -w -E 'PID|com.companyname.mauiapp42' [OUTPUT] USER PID PPID VSZ RSS WCHAN ADDR S NAME u0_a993 12856 1340 15020476 272724 0 0 S com.companyname.mauiapp42 This not only improves memory used to split and parse this information in C#, but adb is also transmitting way less bytes across your USB cable or virtually from an emulator. This feature shipped in recent versions of Visual Studio 2022, improving this scenario for all Xamarin and .NET MAUI customers. Port WindowsAppSDK usage of vcmeta.dll to C# We found that every incremental build of a .NET MAUI project running on Windows spent time in Top 10 most expensive tasks CompileXaml = 3.972 s ... various tasks ... This is the XAML compiler for WindowsAppSDK, that compiles the WinUI3 flavor of XAML (not .NET MAUI XAML). There is very little XAML of this type in .NET MAUI projects, in fact, the only file is Platforms/Windows/App.xaml in the project template. Interestingly, if you installed the Desktop development with C++ workload in the Visual Studio installer, this time just completely went away! Top 10 most expensive tasks ... various tasks ... CompileXaml = 9 ms The WindowsAppSDK XAML compiler p/invokes into a native library from the C++ workload, vcmeta.dll, to calculate a hash for .NET assembly files. This is used to make incremental builds fast — if the hash changes, compile the XAML again. If vcmeta.dll was not found on disk, the XAML compiler was effectively “recompiling everything” on every incremental build. For an initial fix, we simply included a small part of the C++ workload as a dependency of .NET MAUI in Visual Studio. The slightly larger install size was a good tradeoff for saving upwards of 4 seconds in incremental build time. Next, we implemented vcmeta.dll‘s hashing functionality in plain C# with System.Reflection.Metadata to compute indentical hash values as before. Not only was this implementation better, in that we could drop a dependency on the C++ workload, but it was also faster! The time to compute a single hash Method Mean Error StdDev Native 217.31 us 1.704 us 1.594 us Managed 86.43 us 1.700 us 2.210 us Some of the reasons this was faster No p/invoke or COM-interfaces involved. System.Reflection.Metadata has a fast struct-based API, perfect for iterating over types in a .NET assembly and computing a hash value. The end result being that CompileXaml might actually be even faster than 9ms in incremental builds. This feature shipped in WindowsAppSDK 1.3, which is now used by .NET MAUI in .NET 8. See WindowsAppSDK#3128 for details about this improvement. Improvements to remote iOS builds on Windows Comparing inner loop performance for iOS, there was a considerable gap between doing “remote iOS” development on Windows versus doing everything locally on macOS. Many small improvements were made, based on comparing inner-loop .binlog files recorded on macOS versus one recorded inside Visual Studio on Windows. Some examples include maui#12747 don’t explicitly copy files to the build server xamarin-macios#16752 do not copy files to build server for a Delete operation xamarin-macios#16929 batch file deletion via DeleteFilesAsync xamarin-macios#17033 cache AOT compiler path Xamarin/MAUI Visual Studio extension when running dotnet-install.sh on remote build hosts, set the explicit processor flag for M1 Macs. We also made some improvements for all iOS & MacCatalyst projects, such as xamarin-macios#16416 don’t process assemblies over and over again Improvements to Android inner-loop We also made many small improvements to the “inner-loop” on Android — most of which were focused in a specific area. Previously, Xamarin.Forms projects had the luxury of being organized into multiple projects, such as YourApp.Android.csproj Xamarin.Android application project YourApp.iOS.csproj Xamarin.iOS application project YourApp.csproj netstandard2.0 class library Where almost all of the logic for a Xamarin.Forms app was contained in the netstandard2.0 project. Nearly all the incremental builds would be changes to XAML or C# in the class library. This structure enabled the Xamarin.Android MSBuild targets to completely skip many Android-specific MSBuild steps. In .NET MAUI, the “single project” feature means that every incremental build has to run these Android-specific build steps. In focusing specifically improving this area, we made many small changes, such as java-interop#1061 avoid string.Format() java-interop#1064 improve ToJniNameFromAttributesForAndroid java-interop#1065 avoid File.Exists() checks java-interop#1069 fix more places to use TypeDefinitionCache java-interop#1072 use less System.Linq for custom attributes java-interop#1103 use MemoryMappedFile when using Mono.Cecil xamarin-android#7621 avoid File.Exists() checks xamarin-android#7626 perf improvements for LlvmIrGenerator xamarin-android#7652 fast path for <CheckClientHandlerType/> xamarin-android#7653 delay ToJniName when generating AndroidManifest.xml xamarin-android#7686 lazily populate Resource lookup These changes should improve incremental builds in all .NET 8 Android project types. XAML Compilation no longer uses LoadInSeparateAppDomain Looking at the JITStats report in PerfView (for MSBuild.exe) Name JitTime (ms) Microsoft.Maui.Controls.Build.Tasks.dll 214.0 Mono.Cecil 119.0 It appears that Microsoft.Maui.Controls.Build.Tasks.dll was spending a lot of time in the JIT. What was confusing, is this was an incremental build where everything should already be loaded. The JIT’s work should be done already? The cause appears to be usage of the [LoadInSeparateAppDomain] attribute defined by the <XamlCTask/> in .NET MAUI. This is an MSBuild feature that gives MSBuild tasks to run in an isolated AppDomain — with an obvious performance drawback. However, we couldn’t just remove it as there would be complications… [LoadInSeparateAppDomain] also conveniently resets all static state when <XamlCTask/> runs again. Meaning that future incremental builds would potentially use old (garbage) values. There are several places that cache Mono.Cecil objects for performance reasons. Really weird bugs would result if we didn’t address this. So, to actually make this change, we reworked all static state in the XAML compiler to be stored in instance fields & properties instead. This is a general software design improvement, in addition to giving us the ability to safely remove [LoadInSeparateAppDomain]. The results of this change, for an incremental build on a Windows PC Before XamlCTask = 743 ms XamlCTask = 706 ms XamlCTask = 692 ms After XamlCTask = 128 ms XamlCTask = 134 ms XamlCTask = 117 ms This saved about ~587ms on incremental builds on all platforms, an 82% improvement. This will help even more on large solutions with multiple .NET MAUI projects, where <XamlCTask/> runs multiple times. See maui#11982 for further details about this improvement. Performance or App Size Improvements Structs and IEquatable in .NET MAUI Using the Visual Studio’s .NET Object Allocation Tracking profiler on a customer .NET MAUI sample application, we saw Microsoft.Maui.WeakEventManager+Subscription Allocations 686,114 Bytes 21,955,648 This seemed like an exorbitant amount of memory to be used in a sample application’s startup! Drilling in to see where these struct‘s were being created System.Collections.Generic.ObjectEqualityComparer<Microsoft.Maui.WeakEventManager+Subscription>.IndexOf() The underlying problem was this struct didn’t implement IEquatable<T> and was being used as the key for a dictionary. The CA1815 code analysis rule was designed to catch this problem. This is not a rule that is enabled by default, so projects must opt into it. To solve this Subscription is internal to .NET MAUI, and its usage made it possible to be a readonly struct. This was just an extra improvement. We made CA1815 a build error across the entire dotnet/maui repository. We implemented IEquatable<T> for all struct types. After these changes, we could no longer found Microsoft.Maui.WeakEventManager+Subscription in memory snapshots at all. Which saved ~21 MB of allocations in this sample application. If your own projects have usage of struct, it seems quite worthwhile to make CA1815 a build error. A smaller, targeted version of this change was backported to MAUI in .NET 7. See maui#13232 for details about this improvement. Fix performance issue in {AppThemeBinding} Profiling a .NET MAUI sample application from a customer, we noticed a lot of time spent in {AppThemeBinding} and WeakEventManager while scrolling 2.08s (17%) microsoft.maui.controls!Microsoft.Maui.Controls.AppThemeBinding.Apply(object,Microsoft.Maui.Controls.BindableObject,Micr... 2.05s (16%) microsoft.maui.controls!Microsoft.Maui.Controls.AppThemeBinding.AttachEvents() 2.04s (16%) microsoft.maui!Microsoft.Maui.WeakEventManager.RemoveEventHandler(System.EventHandler`1<TEventArgs_REF>,string) The following was happening in this application The standard .NET MAUI project template has lots of {AppThemeBinding} in the default Styles.xaml. This supports Light vs Dark theming. {AppThemeBinding} subscribes to Application.RequestedThemeChanged So, every MAUI view subscribe to this event — potentially multiple times. Subscribers are a Dictionary<string, List<Subscriber>>, where there is a dictionary lookup followed by a O(N) search for unsubscribe operations. There is potentially a usecase here to come up with a generalized “weak event” pattern for .NET. The implementation currently in .NET MAUI came over from Xamarin.Forms, but a generalized pattern could be useful for .NET developers using other UI frameworks. To make this scenario fast, for now, in .NET 8 Before For any {AppThemeBinding}, it calls both RequestedThemeChanged -= OnRequestedThemeChanged O(N) time RequestedThemeChanged += OnRequestedThemeChanged constant time Where the -= is notably slower, due to possibly 100s of subscribers. After Create an _attached boolean, so we know know the “state” if it is attached or not. New bindings only call +=, where -= will now only be called by {AppThemeBinding} in rare cases. Most .NET MAUI apps do not “unapply” bindings, but -= would only be used in that case. See the full details about this fix in maui#14625. See dotnet/runtime#61517 for how we could implement “weak events” in .NET in the future. Address CA1307 and CA1309 for performance Profiling a .NET MAUI sample application from a customer, we noticed time spent during “culture-aware” string operations 77.22ms microsoft.maui!Microsoft.Maui.Graphics.MauiDrawable.SetDefaultBackgroundColor() 42.55ms System.Private.CoreLib!System.String.ToLower() This case, we can improve by simply calling ToLowerInvariant() instead. In some cases you might even consider using string.Equals() with StringComparer.Ordinal. In this case, our code was further reviewed and optimized in Reduce Java interop in MauiDrawable on Android. In .NET 7, we added CA1307 and CA1309 code analysis rules to catch cases like this, but it appears we missed some in Microsoft.Maui.Graphics.dll. These are likely useful rules to enable in your own .NET MAUI applications, as avoiding all culture-aware string operations can be quite impactful on mobile. See maui#14627 for details about this improvement. Address CA1311 for performance After addressing the CA1307 and CA1309 code analysis rules, we took things further and addressed CA1311. As mentioned in the turkish example, doing something like string text = something.ToUpper(); switch (text) { ... } Can actually cause unexpected behavior in Turkish locales, because in Turkish, the character I (Unicode 0049) is considered the upper case version of a different character ý (Unicode 0131), and i (Unicode 0069) is considered the lower case version of yet another character Ý (Unicode 0130). ToLowerInvariant() and ToUpperInvariant() are also better for performance as an invariant ToLower / ToUpper operation is slightly faster. Doing this also avoids loading the current culture, improving startup performance. There are cases where you would want the current culture, such as in a CaseConverter type in .NET MAUI. To do this, you simply have to be explicit in which culture you want to use return ConvertToUpper ? v.ToUpper(CultureInfo.CurrentCulture) v.ToLower(CultureInfo.CurrentCulture); The goal of this CaseConverter is to display upper or lowercase text to a user. So it makes sense to use the CurrentCulture for this. See maui#14773 for details about this improvement. Remove unused ViewAttachedToWindow event on Android Every Label in .NET MAUI was subscribing to public class MauiTextView AppCompatTextView { public MauiTextView(Context context) base(context) { this.ViewAttachedToWindow += MauiTextView_ViewAttachedToWindow; } private void MauiTextView_ViewAttachedToWindow(object? sender, ViewAttachedToWindowEventArgs e) { } //... This was leftover from refactoring, but appeared in dotnet-trace output as 278.55ms (2.4%) mono.android!Android.Views.View.add_ViewAttachedToWindow(System.EventHandler`1<Android.Views.View/ViewAttachedToWindowEv 30.55ms (0.26%) mono.android!Android.Views.View.IOnAttachStateChangeListenerInvoker.n_OnViewAttachedToWindow_Landroid_view_View__mm_wra Where the first is the subscription, and the second is the event firing from Java to C# — only to run an empty managed method. Simply removing this event subscription and empty method, resulted in only a few controls to subscribe to this event as needed 2.76ms (0.02%) mono.android!Android.Views.View.add_ViewAttachedToWindow(System.EventHandler`1<Android.Views.View/ViewAttachedToWindowEv See maui#14833 for details about this improvement. Remove unneeded System.Reflection for {Binding} All bindings in .NET MAUI commonly hit the code path if (property.CanWrite && property.SetMethod.IsPublic && !property.SetMethod.IsStatic) { part.LastSetter = property.SetMethod; var lastSetterParameters = part.LastSetter.GetParameters(); part.SetterType = lastSetterParameters[lastSetterParameters.Length - 1].ParameterType; //... Where ~53% of the time spent applying a binding appeared in dotnet-trace in the MethodInfo.GetParameters() method core.benchmarks!Microsoft.Maui.Benchmarks.BindingBenchmarker.BindName() ... microsoft.maui.controls!Microsoft.Maui.Controls.BindingExpression.SetupPart() System.Private.CoreLib.il!System.Reflection.RuntimeMethodInfo.GetParameters() The above C# is simply finding the property type. It is using a roundabout way of using the property setter’s first parameter, which can be simplified to part.SetterType = property.PropertyType; We could see the results of this change in a BenchmarkDotNet benchmark Method Mean Error StdDev Gen0 Gen1 Allocated –BindName 18.82 us 0.336 us 0.471 us 1.2817 1.2512 10.55 KB ++BindName 18.80 us 0.371 us 0.555 us 1.2512 1.2207 10.23 KB –BindChild 27.47 us 0.542 us 0.827 us 2.0142 1.9836 16.56 KB ++BindChild 26.71 us 0.516 us 0.652 us 1.9226 1.8921 15.94 KB –BindChildIndexer 58.39 us 1.113 us 1.143 us 3.1738 3.1128 26.17 KB ++BindChildIndexer 58.00 us 1.055 us 1.295 us 3.1128 3.0518 25.47 KB Where ++ denotes the new changes. See maui#14830 for further details about this improvement. Use StringComparer.Ordinal for Dictionary and HashSet Profiling a .NET MAUI sample application from a customer, we noticed 4% of the time while scrolling was spent doing dictionary lookups (4.0%) System.Private.CoreLib!System.Collections.Generic.Dictionary<TKey_REF,TValue_REF>.FindValue(TKey_REF) Observing the call stack, some of these were coming from culture-aware string lookups in .NET MAUI microsoft.maui!Microsoft.Maui.PropertyMapper.GetProperty(string) microsoft.maui!Microsoft.Maui.WeakEventManager.AddEventHandler(System.EventHandler<TEventArgs_REF>,string) microsoft.maui!Microsoft.Maui.CommandMapper.GetCommand(string) Which show up in dotnet-trace as a mixture of string comparers (0.98%) System.Private.CoreLib!System.Collections.Generic.NonRandomizedStringEqualityComparer.OrdinalComparer.GetHashCode(string) (0.71%) System.Private.CoreLib!System.String.GetNonRandomizedHashCode() (0.31%) System.Private.CoreLib!System.Collections.Generic.NonRandomizedStringEqualityComparer.OrdinalComparer.Equals(string,stri (0.01%) System.Private.CoreLib!System.Collections.Generic.NonRandomizedStringEqualityComparer.GetStringComparer(object) In cases of Dictionary<string, TValue> or HashSet<string>, we can use StringComparer.Ordinal in many cases to get faster dictionary lookups. This should slightly improve the performance of handlers & all .NET MAUI controls on all platforms. See maui#14900 for details about this improvement. Reduce Java interop in MauiDrawable on Android Profiling a .NET MAUI customer sample while scrolling on a Pixel 5, we saw some interesting time being spent in (0.76%) microsoft.maui!Microsoft.Maui.Graphics.MauiDrawable.OnDraw(Android.Graphics.Drawables.Shapes.Shape,Android.Graphics.Canv (0.54%) microsoft.maui!Microsoft.Maui.Graphics.MauiDrawable.SetDefaultBackgroundColor() This sample has a <Border/> inside a <CollectionView/> and so you can see this work happening while scrolling. Specifically, we reviewed code in .NET MAUI, such as _borderPaint.StrokeWidth = _strokeThickness; _borderPaint.StrokeJoin = _strokeLineJoin; _borderPaint.StrokeCap = _strokeLineCap; _borderPaint.StrokeMiter = _strokeMiterLimit * 2; if (_borderPathEffect != null) _borderPaint.SetPathEffect(_borderPathEffect); This calls from C# to Java five times. Creating a new method in PlatformInterop.java allowed us to reduce it to a single time. We also improved the following method, which would perform many calls from C# to Java // C# void SetDefaultBackgroundColor() { using (var background = new TypedValue()) { if (_context == null || _context.Theme == null || _context.Resources == null) return; if (_context.Theme.ResolveAttribute(globalAndroid.Resource.Attribute.WindowBackground, background, true)) { var resource = _context.Resources.GetResourceTypeName(background.ResourceId); var type = resource?.ToLowerInvariant(); if (type == "color") { var color = new Android.Graphics.Color(ContextCompat.GetColor(_context, background.ResourceId)); _backgroundColor = color; } } } } To be more succinctly implemented in Java as // Java /** * Gets the value of android.R.attr.windowBackground from the given Context * @param context * @return the color or -1 if not found */ public static int getWindowBackgroundColor(Context context) { TypedValue value = new TypedValue(); if (!context.getTheme().resolveAttribute(android.R.attr.windowBackground, value, true) && isColorType(value)) { return value.data; } else { return -1; } } /** * Needed because TypedValue.isColorType() is only API Q+ * https//github.com/aosp-mirror/platform_frameworks_base/blob/1d896eeeb8744a1498128d62c09a3aa0a2a29a16/core/java/android/util/TypedValue.java#L266-L268 * @param value * @return true if the TypedValue is a Color */ private static boolean isColorType(TypedValue value) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return value.isColorType(); } else { // Implementation from AOSP return (value.type >= TypedValue.TYPE_FIRST_COLOR_INT && value.type <= TypedValue.TYPE_LAST_COLOR_INT); } } Which reduces our new implementation on the C# side to be a single Java call and creation of an Android.Graphics.Color struct void SetDefaultBackgroundColor() { var color = PlatformInterop.GetWindowBackgroundColor(_context); if (color != -1) { _backgroundColor = new Android.Graphics.Color(color); } } After these changes, we instead saw dotnet-trace output, such as (0.28%) microsoft.maui!Microsoft.Maui.Graphics.MauiDrawable.OnDraw(Android.Graphics.Drawables.Shapes.Shape,Android.Graphics.Canv (0.04%) microsoft.maui!Microsoft.Maui.Graphics.MauiDrawable.SetDefaultBackgroundColor() This improves the performance of any <Border/> (and other shapes) on Android, and drops about ~1% of the CPU usage while scrolling in this example. See maui#14933 for further details about this improvement. Improve layout performance of Label on Android Testing various .NET MAUI sample applications on Android, we noticed around 5.1% of time spent in PrepareForTextViewArrange() 1.01s (5.1%) microsoft.maui!Microsoft.Maui.ViewHandlerExtensions.PrepareForTextViewArrange(Microsoft.Maui.IViewHandler,Microsoft.Maui 635.99ms (3.2%) mono.android!Android.Views.View.get_Context() Most of the time is spent just calling Android.Views.View.Context to be able to then call into the extension method internal static int MakeMeasureSpecExact(this Context context, double size) { // Convert to a native size to create the spec for measuring var deviceSize = (int)context!.ToPixels(size); return MeasureSpecMode.Exactly.MakeMeasureSpec(deviceSize); } Calling the Context property can be expensive due the interop from C# to Java. Java returns a handle to the instance, then we have to look up any existing, managed C# objects for the Context. If all this work can simply be avoided, it can improve performance dramatically. In .NET 7, we made overloads to ToPixels() that allows you to get the same value with an Android.Views.View So we can instead do internal static int MakeMeasureSpecExact(this PlatformView view, double size) { // Convert to a native size to create the spec for measuring var deviceSize = (int)view.ToPixels(size); return MeasureSpecMode.Exactly.MakeMeasureSpec(deviceSize); } Not only did this change show improvements in dotnet-trace output, but we saw a noticeable difference in our LOLs per second test application from last year See maui#14980 for details about this improvement. Reduce Java interop calls for controls in .NET MAUI Reviewing the beautiful .NET MAUI “Surfing App” sample by @jsuarezruiz We noticed that a lot of time is spent doing Java interop while scrolling 1.76s (35%) Microsoft.Maui!Microsoft.Maui.Platform.WrapperView.DispatchDraw(Android.Graphics.Canvas) 1.76s (35%) Microsoft.Maui!Microsoft.Maui.Platform.ContentViewGroup.DispatchDraw(Android.Graphics.Canvas) These methods were deeply nested doing interop from Java -> C# -> Java many levels deep. In this case, moving some code from C# to Java could make it where less interop would occur; and in some cases no interop at all! So for example, previously DispatchDraw() was overridden in C# to implement clipping behavior // C# // ContentViewGroup is used internally by many .NET MAUI Controls class ContentViewGroup Android.Views.ViewGroup { protected override void DispatchDraw(Canvas? canvas) { if (Clip != null) ClipChild(canvas); base.DispatchDraw(canvas); } } By creating a PlatformContentViewGroup.java, we can do something like // Java /** * Set by C#, determining if we need to call getClipPath() * @param hasClip */ protected final void setHasClip(boolean hasClip) { this.hasClip = hasClip; postInvalidate(); } @Override protected void dispatchDraw(Canvas canvas) { // Only call into C# if there is a Clip if (hasClip) { Path path = getClipPath(canvas.getWidth(), canvas.getHeight()); if (path != null) { canvas.clipPath(path); } } super.dispatchDraw(canvas); } setHasClip() is called when clipping is enabled/disabled on any .NET MAUI control. This allowed the common path to not interop into C# at all, and only views that have opted into clipping would need to. This is very good because dispatchDraw() is called quite often during Android layout, scrolling, etc. This same treatment was also done to a few other internal .NET MAUI types like WrapperView improving the common case, making interop only occur when views have opted into clipping or drop shadows. For testing the impact of these changes, we used Google’s FrameMetricsAggregator that can be setup in any .NET MAUI application’s Platforms/Android/MainActivity.cs // How often in ms you'd like to print the statistics to the console const int Duration = 1000; FrameMetricsAggregator aggregator; Handler handler; protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); handler = new Handler(Looper.MainLooper); // We were interested in the "Total" time, other metrics also available aggregator = new FrameMetricsAggregator(FrameMetricsAggregator.TotalDuration); aggregator.Add(this); handler.PostDelayed(OnFrame, Duration); } void OnFrame() { // We were interested in the "Total" time, other metrics also available var metrics = aggregator.GetMetrics()[FrameMetricsAggregator.TotalIndex]; int size = metrics.Size(); double sum = 0, count = 0, slow = 0; for (int i = 0; i < size; i++) { int value = metrics.Get(i); if (value != 0) { count += value; sum += i * value; if (i > 16) slow += value; Console.WriteLine($"Frame(s) that took ~{i}ms, count {value}"); } } if (sum > 0) { Console.WriteLine($"Average frame time {sum / count0.00}ms"); Console.WriteLine($"No. of slow frames {slow}"); Console.WriteLine("-----"); } handler.PostDelayed(OnFrame, Duration); } FrameMetricsAggregator‘s API is admittedly a bit odd, but the data we get out is quite useful. The result is basically a lookup table where the key is a duration in milliseconds, and the value is the number of “frames” that took that duration. The idea is any frame that takes longer than 16ms is considered “slow” or “janky” as the Android docs sometimes refer. An example of the .NET MAUI “Surfing App” running on a Pixel 5 Before Frame(s) that took ~4ms, count 1 Frame(s) that took ~5ms, count 6 Frame(s) that took ~6ms, count 10 Frame(s) that took ~7ms, count 12 Frame(s) that took ~8ms, count 10 Frame(s) that took ~9ms, count 6 Frame(s) that took ~10ms, count 1 Frame(s) that took ~11ms, count 2 Frame(s) that took ~12ms, count 4 Frame(s) that took ~13ms, count 2 Frame(s) that took ~15ms, count 1 Frame(s) that took ~16ms, count 1 Frame(s) that took ~18ms, count 2 Frame(s) that took ~19ms, count 1 Frame(s) that took ~20ms, count 5 Frame(s) that took ~21ms, count 2 Frame(s) that took ~22ms, count 1 Frame(s) that took ~25ms, count 1 Frame(s) that took ~32ms, count 1 Frame(s) that took ~34ms, count 1 Frame(s) that took ~60ms, count 1 Frame(s) that took ~62ms, count 1 Frame(s) that took ~63ms, count 1 Frame(s) that took ~64ms, count 2 Frame(s) that took ~66ms, count 1 Frame(s) that took ~67ms, count 1 Frame(s) that took ~68ms, count 1 Frame(s) that took ~69ms, count 2 Frame(s) that took ~70ms, count 2 Frame(s) that took ~71ms, count 2 Frame(s) that took ~72ms, count 1 Frame(s) that took ~73ms, count 2 Frame(s) that took ~74ms, count 2 Frame(s) that took ~75ms, count 1 Frame(s) that took ~76ms, count 1 Frame(s) that took ~77ms, count 2 Frame(s) that took ~78ms, count 3 Frame(s) that took ~79ms, count 1 Frame(s) that took ~80ms, count 1 Frame(s) that took ~81ms, count 1 Average frame time 28.67ms No. of slow frames 43 After the changes to ContentViewGroup and WrapperView were in place, we got a very nice improvement! Even in an app making heavy usage of clipping and shadows After Frame(s) that took ~5ms, count 3 Frame(s) that took ~6ms, count 5 Frame(s) that took ~7ms, count 7 Frame(s) that took ~8ms, count 7 Frame(s) that took ~9ms, count 4 Frame(s) that took ~10ms, count 2 Frame(s) that took ~11ms, count 6 Frame(s) that took ~12ms, count 2 Frame(s) that took ~13ms, count 3 Frame(s) that took ~14ms, count 4 Frame(s) that took ~15ms, count 1 Frame(s) that took ~16ms, count 1 Frame(s) that took ~17ms, count 1 Frame(s) that took ~18ms, count 2 Frame(s) that took ~19ms, count 1 Frame(s) that took ~20ms, count 3 Frame(s) that took ~21ms, count 2 Frame(s) that took ~22ms, count 2 Frame(s) that took ~27ms, count 2 Frame(s) that took ~29ms, count 2 Frame(s) that took ~32ms, count 1 Frame(s) that took ~34ms, count 1 Frame(s) that took ~35ms, count 1 Frame(s) that took ~64ms, count 1 Frame(s) that took ~67ms, count 1 Frame(s) that took ~68ms, count 2 Frame(s) that took ~69ms, count 1 Frame(s) that took ~72ms, count 3 Frame(s) that took ~74ms, count 3 Average frame time 21.99ms No. of slow frames 29 See maui#14275 for further detail about these changes. Improve performance of Entry.MaxLength on Android Investigating a .NET MAUI customer sample Navigating from a Shell flyout. To a new page with several Entry controls. There was a noticeable performance delay. When profiling on a Pixel 5, one “hot path” was Entry.MaxLength 18.52ms (0.22%) microsoft.maui!Microsoft.Maui.Platform.EditTextExtensions.UpdateMaxLength(Android.Widget.EditText,Microsoft.Maui.IEntry) 16.03ms (0.19%) microsoft.maui!Microsoft.Maui.Platform.EditTextExtensions.UpdateMaxLength(Android.Widget.EditText,int) 12.16ms (0.14%) microsoft.maui!Microsoft.Maui.Platform.EditTextExtensions.SetLengthFilter(Android.Widget.EditText,int) EditTextExtensions.UpdateMaxLength() calls EditText.Text getter and setter EditTextExtensions.SetLengthFilter() calls EditText.Get/SetFilters() What happens is we end up marshaling strings and IInputFilter[] back and forth between C# and Java for every Entry control. All Entry controls go through this code path (even ones with a default value for MaxLength), so it made sense to move some of this code from C# to Java instead. Our C# code before // C# public static void UpdateMaxLength(this EditText editText, int maxLength) { editText.SetLengthFilter(maxLength); var newText = editText.Text.TrimToMaxLength(maxLength); if (editText.Text != newText) editText.Text = newText; } public static void SetLengthFilter(this EditText editText, int maxLength) { if (maxLength == -1) maxLength = int.MaxValue; var currentFilters = new List<IInputFilter>(editText.GetFilters() ?? new IInputFilter[0]); var changed = false; for (var i = 0; i < currentFilters.Count; i++) { if (currentFilters[i] is InputFilterLengthFilter) { currentFilters.RemoveAt(i); changed = true; break; } } if (maxLength >= 0) { currentFilters.Add(new InputFilterLengthFilter(maxLength)); changed = true; } if (changed) editText.SetFilters(currentFilters.ToArray()); } Moved to Java (with identical behavior) instead // Java /** * Sets the maxLength of an EditText * @param editText * @param maxLength */ public static void updateMaxLength(@NonNull EditText editText, int maxLength) { setLengthFilter(editText, maxLength); if (maxLength < 0) return; Editable currentText = editText.getText(); if (currentText.length() > maxLength) { editText.setText(currentText.subSequence(0, maxLength)); } } /** * Updates the InputFilter[] of an EditText. Used for Entry and SearchBar. * @param editText * @param maxLength */ public static void setLengthFilter(@NonNull EditText editText, int maxLength) { if (maxLength == -1) maxLength = Integer.MAX_VALUE; List<InputFilter> currentFilters = new ArrayList<>(Arrays.asList(editText.getFilters())); boolean changed = false; for (int i = 0; i < currentFilters.size(); i++) { InputFilter filter = currentFilters.get(i); if (filter instanceof InputFilter.LengthFilter) { currentFilters.remove(i); changed = true; break; } } if (maxLength >= 0) { currentFilters.add(new InputFilter.LengthFilter(maxLength)); changed = true; } if (changed) { InputFilter[] newFilter = new InputFilter[currentFilters.size()]; editText.setFilters(currentFilters.toArray(newFilter)); } } This avoids marshaling (copying!) string and array values back and forth from C# to Java. With these changes in place, the calls to EditTextExtensions.UpdateMaxLength() are now so fast they are missing completely from dotnet-trace output, saving ~19ms when navigating to the page in the customer sample. See maui#15614 for details about this improvement. Improve memory usage of CollectionView on Windows We reviewed a .NET MAUI customer sample with a CollectionView of 150,000 data-bound rows. Debugging what happens at runtime, .NET MAUI was effectively doing _itemTemplateContexts = new List<ItemTemplateContext>(capacity 150_000); for (int n = 0; n < 150_000; n++) { _itemTemplateContexts.Add(null); } And then each item is created as it is scrolled into view if (_itemTemplateContexts[index] == null) { _itemTemplateContexts[index] = context = new ItemTemplateContext(...); } return _itemTemplateContexts[index]; This wasn’t the best approach, but to improve things use a Dictionary<int, T> instead, just let it size dynamically. use TryGetValue(..., out var context), so each call accesses the indexer one less time than before. use either the bound collection’s size or 64 (whichever is smaller) as a rough estimate of how many might fit on screen at a time Our code changes to if (!_itemTemplateContexts.TryGetValue(index, out var context)) { _itemTemplateContexts[index] = context = new ItemTemplateContext(...); } return context; With these changes in place, a memory snapshot of the app after startup Before Heap Size 82,899.54 KB After Heap Size 81,768.76 KB Which is saving about 1MB of memory on launch. In this case, it feels better to just let the Dictionary size itself with an estimate of what capacity will be. See maui#16838 for details about this improvement. Use UnmanagedCallersOnlyAttribute on Apple platforms When unmanaged code calls into managed code, such as invoking a callback from Objective-C, the [MonoPInvokeCallbackAttribute] was previously used in Xamarin.iOS, Xamarin.Mac, and .NET 6+ for this purpose. The [UnmanagedCallersOnlyAttribute] attribute came along as a modern replacement for this Mono feature, which is implemented in a way with performance in mind. Unfortunately, there are a few restrictions when using this new attribute Method must be marked static. Must not be called from managed code. Must only have blittable arguments. Must not have generic type parameters or be contained within a generic class. Not only did we have to refactor the “code generator” that produces many of the bindings for Apple APIs for AppKit, UIKit, etc., but we also had many manual bindings that would need the same treatment. The end result is that most callbacks from Objective-C to C# should be faster in .NET 8 than before. See xamarin-macios#10470 and xamarin-macios#15783 for details about these improvements. Faster Java interop for strings on Android When binding members which have parameter types or return types which are java.lang.CharSequence, the member is “overloaded” to replace CharSequence with System.String, and the “original” member has a Formatted suffix. For example, consider android.widget.TextView, which has getText() and setText() methods which have parameter types and return types which are java.lang.CharSequence // Java class TextView extends View { public CharSequence getText(); public final void setText(CharSequence text); } When bound, this results in two properties // C# class TextView View { public Java.Lang.ICharSequence? TextFormatted { get; set; } public string? Text { get; set; } } The “non-Formatted overload” works by creating a temporary String object to invoke the Formatted overload, so the actual implementation looks like partial class TextView { public string? Text { get => TextFormatted?.ToString (); set { var jls = value == null ? null new Java.Lang.String (value); TextFormatted = jls; jls?.Dispose (); } } } TextView.Text is much easer to understand & simpler to consume for .NET developers than TextView.TextFormatted. A problem with the this approach is performance creating a new Java.Lang.String instance requires Creating the managed peer (the Java.Lang.String instance), Creating the native peer (the java.lang.String instance), And registering the mapping between (1) and (2) And then immediately use and dispose the value… This is particularly noticeable with .NET MAUI apps. Consider a customer sample, which uses XAML to set data-bound Text values in a CollectionView, which eventually hit TextView.Text. Profiling shows 653.69ms (6.3%) mono.android!Android.Widget.TextView.set_Text(string) 198.05ms (1.9%) mono.android!Java.Lang.String..ctor(string) 121.57ms (1.2%) mono.android!Java.Lang.Object.Dispose() 6.3% of scrolling time is spent in the TextView.Text property setter! Partially optimize this case if the *Formatted member is (1) a property, and (2) not virtual, then we can directly call the Java setter method. This avoids the need to create a managed peer and to register a mapping between the peers partial class TextView { public string? Text { get => TextFormatted?.ToString (); // unchanged set { const string __id = "setText.(Ljava/lang/CharSequence;)V"; JniObjectReference native_value = JniEnvironment.Strings.NewString (value); try { JniArgumentValue* __args = stackalloc JniArgumentValue [1]; __args [0] = new JniArgumentValue (native_value); _members.InstanceMethods.InvokeNonvirtualVoidMethod (__id, this, __args); } finally { JniObjectReference.Dispose (ref native_value); } } } } With the result being Method Mean Error StdDev Allocated Before SetFinalText 6.632 us 0.0101 us 0.0079 us 112 B After SetFinalText 1.361 us 0.0022 us 0.0019 us – The TextView.Text property setter invocation time is reduced to 20% of the previous average invocation time. Note that the virtual case is problematic for other reasons, but luckily enough TextView.setText() is non-virtual and likely one of the more commonly used Android APIs. See java-interop#1101 for details about this improvement. Faster Java interop for C# events on Android Profiling a .NET MAUI customer sample while scrolling on a Pixel 5, We saw ~2.2% of the time spent in the IOnFocusChangeListenerImplementor constructor, due to a subscription to the View.FocusChange event (2.2%) mono.android!Android.Views.View.IOnFocusChangeListenerImplementor..ctor() MAUI subscribes to Android.Views.View.FocusChange for every view placed on the screen, which happens while scrolling in this sample. Reviewing the generated code for the IOnFocusChangeListenerImplementor constructor, we see it still uses outdated JNIEnv APIs public IOnFocusChangeListenerImplementor () base ( Android.Runtime.JNIEnv.StartCreateInstance ("mono/android/view/View_OnFocusChangeListenerImplementor", "()V"), JniHandleOwnership.TransferLocalRef ) { Android.Runtime.JNIEnv.FinishCreateInstance (((Java.Lang.Object) this).Handle, "()V"); } Which we can change to use the newer/faster Java.Interop APIs public unsafe IOnFocusChangeListenerImplementor () base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) { const string __id = "()V"; if (((Java.Lang.Object) this).Handle != IntPtr.Zero) return; var h = JniPeerMembers.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); SetHandle (h.Handle, JniHandleOwnership.TransferLocalRef); JniPeerMembers.InstanceMethods.FinishCreateInstance (__id, this, null); } These are better because the equivalent call to JNIEnv.FindClass() is cached, among other things. This was just one of the cases that was accidentally missed when we implemented the new Java.Interop APIs in the Xamarin timeframe. We simply needed to update our code generator to emit a better C# binding for this case. After these changes, we saw instead results in dotnet-trace (0.81%) mono.android!Android.Views.View.IOnFocusChangeListenerImplementor..ctor() This should improve the performance of all C# events that wrap Java listeners, a design-pattern commonly used in Java and Android applications. This includes the FocusedChanged event used by all .NET MAUI views on Android. See java-interop#1105 for details about this improvement. Use Function Pointers for JNI There is various machinery and generated code that makes Java interop possible from C#. Take, for example, the following instance method foo() in Java // Java object foo(object bar) { // returns some value } A C# method named CallObjectMethod is responsible for calling Java’s Native Interface (JNI) that calls into the JVM to actually invoke the Java method public static unsafe JniObjectReference CallObjectMethod (JniObjectReference instance, JniMethodInfo method, JniArgumentValue* args) { //... IntPtr thrown; var tmp = NativeMethods.java_interop_jnienv_call_object_method_a (JniEnvironment.EnvironmentPointer, out thrown, instance.Handle, method.ID, (IntPtr) args); Exception __e = JniEnvironment.GetExceptionForLastThrowable (thrown); if (__e != null) ExceptionDispatchInfo.Capture (__e).Throw (); JniEnvironment.LogCreateLocalRef (tmp); return new JniObjectReference (tmp, JniObjectReferenceType.Local); } In Xamarin.Android, .NET 6, and .NET 7 all calls into Java went through a java_interop_jnienv_call_object_method_a p/invoke, which signature looks like [DllImport (JavaInteropLib, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] internal static extern unsafe jobject java_interop_jnienv_call_object_method_a (IntPtr jnienv, out IntPtr thrown, jobject instance, IntPtr method, IntPtr args); Which is implemented in C as JI_API jobject java_interop_jnienv_call_object_method_a (JNIEnv *env, jthrowable *_thrown, jobject instance, jmethodID method, jvalue* args) { *_thrown = 0; jobject _r_ = (*env)->CallObjectMethodA (env, instance, method, args); *_thrown = (*env)->ExceptionOccurred (env); return _r_; } C# 9 introduced function pointers that allowed us a way to simplify things slightly — and make them faster as a result. So instead of using p/invoke in .NET 8, we could instead call a new unsafe method named CallObjectMethodA // Before var tmp = NativeMethods.java_interop_jnienv_call_object_method_a (JniEnvironment.EnvironmentPointer, out thrown, instance.Handle, method.ID, (IntPtr) args); // After var tmp = JniNativeMethods.CallObjectMethodA (JniEnvironment.EnvironmentPointer, instance.Handle, method.ID, (IntPtr) args); Which calls a C# function pointer directly [System.Runtime.CompilerServices.MethodImpl (System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] internal static unsafe jobject CallObjectMethodA (IntPtr env, jobject instance, IntPtr method, IntPtr args) { return (*((JNIEnv**)env))->CallObjectMethodA (env, instance, method, args); } This function pointer declared using the new syntax introduced in C# 9 public delegate* unmanaged <IntPtr, jobject, IntPtr, IntPtr, jobject> CallObjectMethodA; Comparing the two implementations with a manual benchmark # JIPinvokeTiming timing 000001.6993644 # Average Invocation 0.00016993643999999998ms # JIFunctionPointersTiming timing 000001.6561349 # Average Invocation 0.00016561349ms With a Release build, the average invocation time for JIFunctionPointersTiming takes 97% of the time as JIPinvokeTiming, i.e. is 3% faster. Additionally, using C# 9 function pointers means we can get rid of all of the java_interop_jnienv_*() C functions, which shrinks libmonodroid.so by ~55KB for each architecture. See xamarin-android#8234 and java-interop#938 for details about this improvement. Removed Xamarin.AndroidX.Legacy.Support.V4 Reviewing .NET MAUI’s Android dependencies, we noticed a suspicious package Xamarin.AndroidX.Legacy.Support.V4 If you are familiar with the Android Support Libraries, these are a set of packages Google provides to “polyfill” APIs to past versions of Android. This gives them a way to bring new APIs to old OS versions, since the Android ecosystem (OEMs, etc.) are much slower to upgrade as compared to iOS, for example. This particular package, Legacy.Support.V4, is actually support for Android as far back as Android API 4! The minimum supported Android version in .NET is Android API 21, which was released in 2017. It turns out this dependency was brought over from Xamarin.Forms and was not actually needed. As expected from this change, lots of Java code was removed from .NET MAUI apps. So much, in fact, that .NET 8 MAUI applications are now under the multi-dex limit — all Dalvik bytecode can fix into a single classes.dex file. A detailed breakdown of the size changes using apkdiff > apkdiff -f com.companyname.maui_before-Signed.apk com.companyname.maui_after-Signed.apk Size difference in bytes ([*1] apk1 only, [*2] apk2 only) + 1,598,040 classes.dex - 6 META-INF/androidx.asynclayoutinflater_asynclayoutinflater.version *1 - 6 META-INF/androidx.legacy_legacy-support-core-ui.version *1 - 6 META-INF/androidx.legacy_legacy-support-v4.version *1 - 6 META-INF/androidx.media_media.version *1 - 455 assemblies/assemblies.blob - 564 res/layout/notification_media_action.xml *1 - 744 res/layout/notification_media_cancel_action.xml *1 - 1,292 res/layout/notification_template_media.xml *1 - 1,584 META-INF/BNDLTOOL.SF - 1,584 META-INF/MANIFEST.MF - 1,696 res/layout/notification_template_big_media.xml *1 - 1,824 res/layout/notification_template_big_media_narrow.xml *1 - 2,456 resources.arsc - 2,756 res/layout/notification_template_media_custom.xml *1 - 2,872 res/layout/notification_template_lines_media.xml *1 - 3,044 res/layout/notification_template_big_media_custom.xml *1 - 3,216 res/layout/notification_template_big_media_narrow_custom.xml *1 - 2,030,636 classes2.dex Summary - 24,111 Other entries -0.35% (of 6,880,759) - 432,596 Dalvik executables -3.46% (of 12,515,440) + 0 Shared libraries 0.00% (of 12,235,904) - 169,179 Package size difference -1.12% (of 15,123,185) See dotnet/maui#12232 for details about this improvement. Deduplication of generics on iOS and macOS In .NET 7, iOS applications experienced app size increases due to C# generics usage across multiple .NET assemblies. When the .NET 7 Mono AOT compiler encounters a generic instance that is not handled by generic sharing, it will emit code for the instance. If the same instance is encountered during AOT compilation in multiple assemblies, the code will be emitted multiple times, increasing code size. In .NET 8, new dedup-skip and dedup-include command-line options are passed to the Mono AOT compiler. A new aot-instances.dll assembly is created for sharing this information in one place throughout the application. The change was tested on MySingleView app and Monotouch tests in the xamarin/xamarin-macios codebase App Baseline size on disk .ipa (MB) Target size on disk .ipa (MB) Baseline size on disk .app (MB) Target size on disk .app (MB) Baseline build time (s) Target build time (s) .app diff (%) MySingleView Release iOS 5.4 5.4 29.2 15.2 29.2 16.8 47.9 MySingleView Release iOSSimulator-arm64 N/A N/A 469.5 341.8 468.0 330.0 27.2 Monotouch Release llvm iOS 49.0 38.8 209.6 157.4 115.0 130.0 24.9 See xamarin-macios#17766 for details about this improvement. Fix System.Linq.Expressions implementation on iOS-like platforms In .NET 7, codepaths in System.Linq.Expressions were controlled by various flags such as CanCompileToIL CanEmitObjectArrayDelegate CanCreateArbitraryDelegates These flags were controlling codepaths which are “AOT friendly” and those that are not. For desktop platforms, NativeAOT specifies the following configuration for AOT-compatible code <IlcArg Include="--featureSystem.Linq.Expressions.CanCompileToIL=false" /> <IlcArg Include="--featureSystem.Linq.Expressions.CanEmitObjectArrayDelegate=false" /> <IlcArg Include="--featureSystem.Linq.Expressions.CanCreateArbitraryDelegates=false" /> When it comes to iOS-like platforms, System.Linq.Expressions library was built with constant propagation enabled and control variables were removed. This further caused above-listed NativeAOT feature switches not to have any effect (fail to trim during app build), potentially causing the AOT compilation to follow unsupported code paths on these platforms. In .NET8, we have unified the build of System.Linq.Expressions.dll shipping the same assembly for all supported platforms and runtimes, and simplified these switches to respect IsDynamicCodeSupported so that the .NET trimmer can remove the appropriate IL in System.Linq.Expressions.dll at application build time. See dotnet/runtime#87924 and dotnet/runtime#89308 for details about this improvement. Set DynamicCodeSupport=false for iOS and Catalyst In .NET 8, the feature switch $(DynamicCodeSupport) is set to false for platforms Where it is not possible to publish without the AOT compiler. When interpreter is not enabled. Which boils down to applications running on iOS, tvOS, MacCatalyst, etc. DynamicCodeSupport=false enables the .NET trimmer to remove code paths depending on RuntimeFeature.IsDynamicCodeSupported such as this example in System.Linq.Expressions. Estimated size savings are dotnet new maui (ios) old SLE.dll new SLE.dll + DynamicCodeSupported=false diff (%) Size on disk (Mb) 40,53 38,78 -4,31% .pkg (Mb) 14,83 14,20 -4,21% When combined with the System.Linq.Expressions improvements on iOS-like platforms, this showed a nice overall improvement to application size See xamarin-macios#18555 for details about this improvement. Memory Leaks Memory Leaks and Quality Given that the major theme for .NET MAUI in .NET 8 is quality, memory-related issues became a focal point for this release. Some of the problems found existed even in the Xamarin.Forms codebase, so we are happy to work towards a framework that developers can rely on for their cross-platform .NET applications. For full details on the work completed in .NET 8, we’ve various PRs and Issues related to memory issues at Pull Requests Issues You can see that considerable progress was made in .NET 8 in this area. If we compare .NET 7 MAUI versus .NET 8 MAUI in a sample application running on Windows, displaying the results of GC.GetTotalMemory() on screen Then compare the sample application running on macOS, but with many more pages pushed onto the navigation stack See the sample code for this project on GitHub for further details. Diagnosing leaks in .NET MAUI The symptom of a memory leak in a .NET MAUI application, could be something like Navigate from the landing page to a sub page. Go back. Navigate to the sub page again. Repeat. Memory grows consistently until the OS closes the application due to lack of memory. In the case of Android, you may see log messages such as 07-07 185139.090 17079 17079 D Mono GC_MAJOR (user request) time 137.21ms, stw 140.60ms los size 10984K in use 3434K 07-07 185139.090 17079 17079 D Mono GC_MAJOR_SWEEP major size 116192K in use 108493K 07-07 185139.092 17079 17079 I monodroid-gc 46204 outstanding GREFs. Performing a full GC! In this example, a 116MB heap is quite large for a mobile application, as well as over 46,000 C# <-> Java wrapper objects! To truly determine if the sub page is leaking, we can make a couple modifications to a .NET MAUI application Add logging in a finalizer. For example ~MyPage() => Console.WriteLine("Finalizer for ~MyPage()"); While navigating through your app, you can find out if entire pages are living forever if the log message is never displayed. This is a common symptom of a leak, because any View holds .Parent.Parent.Parent, etc. all the way up to the Page object. Call GC.Collect() somewhere in the app, such as the sub page’s constructor public MyPage() { GC.Collect(); // For debugging purposes only, remove later InitializeComponent(); } This makes the GC more deterministic, in that we are forcing it to run more frequently. Each time we navigate to the sub page, we are more likely causing the old sub page’s to go away. If things are working properly, we should see the log message from the finalizer. Note GC.Collect() is for debugging purposes only. You should not need this in your app after investigation is complete, so be sure to remove it afterward. With these changes in place, test a Release build of your app. On iOS, Android, macOS, etc. you can watch console output of your app to determine what is actually happening at runtime. adb logcat, for example, is a way to view these logs on Android. If running on Windows, you can also use Debug > Windows > Diagnostic Tools inside Visual Studio to take memory snapshots inside Visual Studio. In the future, we would like Visual Studio’s diagnostic tooling to support .NET MAUI applications running on other platforms. See our memory leaks wiki page for more information related to memory leaks in .NET MAUI applications. Patterns that cause leaks C# events C# events, just like a field, property, etc. can create strong references between objects. Let’s look at a situation where things can go wrong. Take for example, the cross-platform Grid.ColumnDefinitions property public class Grid Layout, IGridLayout { public static readonly BindableProperty ColumnDefinitionsProperty = BindableProperty.Create("ColumnDefinitions", typeof(ColumnDefinitionCollection), typeof(Grid), null, validateValue (bindable, value) => value != null, propertyChanged UpdateSizeChangedHandlers, defaultValueCreator bindable => { var colDef = new ColumnDefinitionCollection(); colDef.ItemSizeChanged += ((Grid)bindable).DefinitionsChanged; return colDef; }); public ColumnDefinitionCollection ColumnDefinitions { get { return (ColumnDefinitionCollection)GetValue(ColumnDefinitionsProperty); } set { SetValue(ColumnDefinitionsProperty, value); } } Grid has a strong reference to its ColumnDefinitionCollection via the BindableProperty. ColumnDefinitionCollection has a strong reference to Grid via the ItemSizeChanged event. If you put a breakpoint on the line with ItemSizeChanged +=, you can see the event has an EventHandler object where the Target is a strong reference back to the Grid. In some cases, circular references like this are completely OK. The .NET runtime(s)’ garbage collectors know how to collect cycles of objects that point each other. When there is no “root” object holding them both, they can both go away. The problem comes in with object lifetimes what happens if the ColumnDefinitionCollection lives for the life of the entire application? Consider the following Style in Application.Resources or Resources/Styles/Styles.xaml <Style TargetType="Grid" xKey="GridStyleWithColumnDefinitions"> <Setter Property="ColumnDefinitions" Value="18,*"/> </Style> If you applied this Style to a Grid on a random Page Application‘s main ResourceDictionary holds the Style. The Style holds a ColumnDefinitionCollection. The ColumnDefinitionCollection holds the Grid. Grid unfortunately holds the Page via .Parent.Parent.Parent, etc. This situation could cause entire Page‘s to live forever! Note The issue with Grid is fixed in maui#16145, but is an excellent example of illustrating how C# events can go wrong. Circular references on Apple platforms Even since the early days of Xamarin.iOS, there has existed an issue with “circular references” even in a garbage-collected runtime like .NET. C# objects co-exist with a reference-counted world on Apple platforms, and so a C# object that subclasses NSObject can run into situations where they can accidentally live forever — a memory leak. This is not a .NET-specific problem, as you can just as easily create the same situation in Objective-C or Swift. Note that this does not occur on Android or Windows platforms. Take for example, the following circular reference class MyViewSubclass UIView { public UIView? Parent { get; set; } public void Add(MyViewSubclass subview) { subview.Parent = this; AddSubview(subview); } } //... var parent = new MyViewSubclass(); var view = new MyViewSubclass(); parent.Add(view); In this case parent -> view via Subviews view -> parent via the Parent property The reference count of both objects is non-zero. Both objects live forever. This problem isn’t limited to a field or property, you can create similar situations with C# events class MyView UIView { public MyView() { var picker = new UIDatePicker(); AddSubview(picker); picker.ValueChanged += OnValueChanged; } void OnValueChanged(object? sender, EventArgs e) { } // Use this instead and it doesn't leak! //static void OnValueChanged(object? sender, EventArgs e) { } } In this case MyView -> UIDatePicker via Subviews UIDatePicker -> MyView via ValueChanged and EventHandler.Target Both objects live forever. A solution for this example, is to make OnValueChanged method static, which would result in a null Target on the EventHandler instance. Another solution, would be to put OnValueChanged in a non-NSObject subclass class MyView UIView { readonly Proxy _proxy = new(); public MyView() { var picker = new UIDatePicker(); AddSubview(picker); picker.ValueChanged += _proxy.OnValueChanged; } class Proxy { public void OnValueChanged(object? sender, EventArgs e) { } } } This is the pattern we’ve used in most .NET MAUI handlers and other UIView subclasses. See the MemoryLeaksOniOS sample repo, if you would like to play with some of these scenarios in isolation in an iOS application without .NET MAUI. Roslyn analyzer for Apple platforms We also have an experimental Roslyn Analyzer that can detect these situations at build time. To add it to net7.0-ios, net8.0-ios, etc. projects, you can simply install a NuGet package <PackageReference Include="MemoryAnalyzers" Version="0.1.0-beta.3" PrivateAssets="all" /> Some examples of a warning would be public class MyView UIView { public event EventHandler MyEvent; } Event 'MyEvent' could could memory leaks in an NSObject subclass. Remove the event or add the [UnconditionalSuppressMessage("Memory", "MA0001")] attribute with a justification as to why the event will not leak. Note that the analyzer can warns if there might be an issue, so it can be quite noisy to enable in a large, existing codebase. Inspecting memory at runtime is the best way to determine if there is truly a memory leak. Tooling and Documentation Simplified dotnet-trace and dotnet-dsrouter In .NET 7, profiling a mobile application was a bit of a challenge. You had to run dotnet-dsrouter and dotnet-trace together and get all the settings right to be able to retrieve a .nettrace or speedscope file for performance investigations. There was also no built-in support for dotnet-gcdump to connect to dotnet-dsrouter to get memory snapshots of a running .NET MAUI application. In .NET 8, we’ve streamlined this scenario by making new commands for dotnet-dsrouter that simplifies the workflow. To verify you have the latest diagnostic tooling, you can install them via $ dotnet tool install -g dotnet-dsrouter You can invoke the tool using the following command dotnet-dsrouter Tool 'dotnet-dsrouter' was successfully installed. $ dotnet tool install -g dotnet-gcdump You can invoke the tool using the following command dotnet-gcdump Tool 'dotnet-gcdump' was successfully installed. $ dotnet tool install -g dotnet-trace You can invoke the tool using the following command dotnet-trace Tool 'dotnet-trace' was successfully installed. Verify you have at least 8.x versions of these tools $ dotnet tool list -g Package Id Version Commands -------------------------------------------------------------------------------------- dotnet-dsrouter 8.0.452401 dotnet-dsrouter dotnet-gcdump 8.0.452401 dotnet-gcdump dotnet-trace 8.0.452401 dotnet-trace To profile an Android application on an Android emulator, first build and install your application in Release mode such as $ dotnet build -f net8.0-android -tInstall -c Release -pAndroidEnableProfiler=true Build SUCCEEDED. 0 Warning(s) 0 Error(s) Next, open a terminal to run dotnet-dsrouter $ dotnet-dsrouter android-emu Start an application on android emulator with one of the following environment variables set DOTNET_DiagnosticPorts=10.0.2.29000,nosuspend,connect DOTNET_DiagnosticPorts=10.0.2.29000,suspend,connect Then in a second terminal window, we can set the debug.mono.profile Android system property, as the stand-in for $DOTNET_DiagnosticPorts $ adb shell setprop debug.mono.profile '10.0.2.29000,suspend,connect' $ dotnet-trace ps 3248 dotnet-dsrouter $ dotnet-trace collect -p 3248 --format speedscope ... [00000009] Recording trace 3.2522 (MB) Press <Enter> or <Ctrl+C> to exit... Note Android doesn’t have good support for environment variables like $DOTNET_DiagnosticPorts. You can create an AndroidEnvironment text file for setting environment variables, but Android system properties can be simpler as they would not require rebuilding the application to set them. Upon launching the Android application, it should be able to connect to dotnet-dsrouter -> dotnet-trace and record performance profiling information for investigation. The --format argument is optional and it defaults to .nettrace. However, .nettrace files can be viewed only with Perfview on Windows, while the speedscope JSON files can be viewed “on” macOS or Linux by uploading them to https//speedscope.app. Note When providing a process ID to dotnet-trace, it knows how to tell if a process ID is dotnet-dsrouter and connect through it appropriately. dotnet-dsrouter has the following new commands to simplify the workflow dotnet-dsrouter android Android devices dotnet-dsrouter android-emu Android emulators dotnet-dsrouter ios iOS devices dotnet-dsrouter ios-sim iOS simulators See the .NET MAUI wiki for more information about profiling .NET MAUI applications on each platform. dotnet-gcdump Support for Mobile In .NET 7, we had a somewhat complex method (see wiki) for getting a memory snapshot of an application on the Mono runtime (such as iOS or Android). You had to use a Mono-specific event provider such as dotnet-trace collect --diagnostic-port /tmp/maui-app --providers Microsoft-DotNETRuntimeMonoProfiler0xC9000014 And then we relied on Filip Navara’s mono-gcdump tool (thanks Filip!) to convert the .nettrace file to .gcdump to be opened in Visual Studio or PerfView. In .NET 8, we now have dotnet-gcdump support for mobile scenarios. If you want to get a memory snapshot of a running application, you can use dotnet-gcdump in a similar fashion as dotnet-trace $ dotnet-gcdump ps 3248 dotnet-dsrouter $ dotnet-gcdump collect -p 3248 Writing gcdump to '20231018_115631_29880.gcdump'... Note This requires the exact same setup as dotnet-trace, such as -pAndroidEnableProfiler=true, dotnet-dsrouter, adb commands, etc. This greatly streamlines our workflow for investigating memory leaks in .NET MAUI applications. See our memory leaks wiki page for more information. The post .NET 8 Performance Improvements in .NET MAUI appeared first on .NET Blog.


Solved: docker-compose build asp.net core 3.0 erro ...
Category: Docker

Problem The .NET Core frameworks can be found at <pre class="language-mar ...


Views: 2666 Likes: 150
 The .NET Stacks #33: ?? A blazing conversation with Steve Sanderson
The .NET Stacks #33 ?? A blazing conversation wi ...

Happy Monday, all. What did you get NuGet for its 10th birthday?This weekMicrosoft blogs about more .NET 5 improvementsA study on migrating a hectic service to .NET CoreMeet Jab, a new compile-time DI libraryDev Discussions Steve SandersonLast week in the .NET worldMicrosoft blogs about more .NET 5 improvementsThis week, Microsoft pushed a few more blog posts to promote .NET 5 improvements Sourabh Shirhatti wrote about diagnostic improvements, and Mána Píchová writes about .NET networking improvements.Diagnostic improvementsWith .NET 5, the diagnostic suite of tools does not require installing them as .NET global tools—they can now be installed without the .NET SDK. There’s now a single-file distribution mechanism that only requires a runtime of .NET Core 3.1 or higher. You can check out the GitHub repo to geek out on all the available diagnostics tools. In other news, you can now perform startup tracing from EventPipe as the tooling can now suspend the runtime during startup until a tool is connected. Check out the blog post for the full treatment.Networking improvementsIn terms of .NET 5 networking improvements, the team added the ability to use cancellation timeouts from HttpClient without the need for a custom CancellationToken. While the client still throws a TaskCanceledException, the inner exception is a TimeoutException when timeouts occur. .NET 5 also supports multiple connections with HTTP/2, a configurable ping mechanism, experimental support for HTTP/3, and various telemetry improvements. Check out the networking blog post for details. It’s a nice complement to Stephen Toub’s opus about .NET 5 performance improvements.A study on migrating a hectic service to .NET CoreThis week, Avanindra Paruchuri wrote about migrating the Azure Active Directory gateway—and its 115 billion daily requests—over to .NET Core. While there’s nothing preventing you hosting .NET Framework apps in the cloud, the bloat of the framework often leads to expensive cloud spend.The gateway’s scale of execution results in significant consumption of compute resources, which in turn costs money. Finding ways to reduce the cost of executing the service has been a key goal for the team behind it. The buzz around .NET Core’s focus on performance caught our attention, especially since TechEmpower listed ASP.NET Core as one of the fastest web frameworks on the planet.In Azure AD gateway’s case, we were able to cut our CPU costs by 50%. As a result of the gains in throughput, we were able to reduce our fleet size from ~40k cores to ~20k cores (50% reduction) … Our CPU usage was reduced by half on .NET Core 3.1 compared to .NET Framework 4.6.2 (effectively doubling our throughput).It’s a nice piece on how they were able to gradually move over and gotchas they learned along the way.Meet Jab, a new compile-time DI libraryThis week, Pavel Krymets introduced Jab, a library used for compile-time dependency injection. Pavel works with the Azure SDKs and used to work on the ASP.NET Core team. Remember a few weeks ago, when we said that innovation in C# source generators will be coming in 2021? Here we go.From the GitHub readme, it promises fast startup (200x more than Microsoft.Extensions.DependencyInjection), fast resolution (a 7x improvement), no runtime dependencies, with all code generating during project compilation. Will it run on ASP.NET Core? Not likely, since ASP.NET Core is heavily dependent on the runtime thanks to type accessibility and dependency discovery, but Pavel wonders if there’s a middle ground.Dev Discussions Steve SandersonIt seems like forever ago when, at NDC Oslo in 2017, Steve Sanderson showed off a new web UI framework with the caveat “an experiment, something for you to be amused by.” By extending Dot Net Anywhere (DNA), Chris Bacon’s portable .NET runtime, on WebAssembly, he was able to load and run C# in the browser. In the browser!Of course, this amusing experiment has grown into Blazor, a robust system for writing web UIs in C#. I was happy to talk to Steve Sanderson about his passions for the front-end web, how far Blazor has come, and what’s coming to Blazor in .NET 6.Years ago, you probably envisioned what Blazor could be. Has it met its potential, or are there other areas to focus on?We’re not there yet. If you go on YouTube and find the first demo I ever did of Blazor at NDC Oslo in 2017, you’ll see my original prototype had near-instant live reloading while coding, and the download size was really tiny. I still aspire to get the real version of Blazor to have those characteristics. Of course, the prototype had the advantage of only needing to do a tiny number of things—creating a production-capable version is 100x more work, which is why it hasn’t yet got there, but has of course exceeded the prototype vastly in more important ways.Good news though is that in .NET 6 we expect to ship an even better version of live-updating-while-coding than I had in that first prototype, so it’s getting there!When looking at AOT, you’ll see increased performance but a larger download size. Do you see any other tradeoffs developers will need to consider?The mixed-mode flavour of AOT, in which some of your code is interpreted and some is AOT, allows for a customizable tradeoff between size and speed, but also includes some subtleties like extra overhead when calling from AOT to interpreted code and vice-versa.Also, when you enable AOT, your app’s publish time may go up substantially (maybe by 5-10 minutes, depending on code size) because the whole Emscripten toolchain just takes that long. This wouldn’t affect your daily development flow on your own machine, but likely means your CI builds could take longer.It’s still quite impressive to see the entire .NET runtime run in the browser for Blazor Web Assembly. That comes with an upfront cost, as we know. I know that the Blazor team has done a ton of work to help lighten the footprint and speed up performance. With the exception of AOT, do you envision more work on this? Do you see a point where it’ll be as lightweight as other leading front-end frameworks, or will folks need to understand it’s a cost that comes with a full framework in the browser?The size of the .NET runtime isn’t ever going to reduce to near-zero, so JS-based microframeworks (whose size could be just a few KB) are always going to be smaller. We’re not trying to win outright based on size alone—that would be madness. Blazor WebAssembly is aimed to be maximally productive for developers while being small enough to download that, in very realistic business app scenarios, the download size shouldn’t be any reason for concern.That said, it’s conceivable that new web platform features like Signed HTTP Exchanges could let us smartly pre-load the .NET WebAssembly runtime in a browser in the background (directly from some Microsoft CDN) while you’re visiting a Blazor WebAssembly site, so that it’s instantly available at zero download size when you go to other Blazor WebAssembly sites. Signed HTTP Exchanges allow for a modern equivalent to the older idea of a cross-site CDN cache. We don’t have a definite plan about that yet as not all browsers have added support for it.Check out the entire interview at my site.?? Last week in the .NET world?? The Top 3Andrew Lock introduces the ASP.NET Core Data Protection system.Maarten Balliauw writes about building a friendly .NET SDK.Josef Ottosson writes an Azure Function to zip multiple files from Azure Storage.?? AnnouncementsShelley Bransten announces Microsoft Cloud for Retail.Christopher Gill celebrates NuGet’s 10th birthday.Tara Overfield releases the January 2021 Security and Quality Rollup Updates for .NET Framework, and Rahul Bhandari writes about the .NET January 2021 updates..NET 6 nightly builds for Apple M1 are now available.The Visual Studio team wants your feedback on Razor syntax coloring.?? Community and eventsThe .NET Docs Show talks to Luis Quintanilla about F#.Pavel Krymets introduces Jab, a compile-time DI container.The Entity Framework Standup talks about EF Core 6 survey results, and the Languages & Runtime standup discusses plans for .NET 6 and VB source generators.Sarah Novotny writes about 4 open source lessons for 2021.IdentityServer v5 has shipped.Khalid Abuhakmeh rethinks OSS attribution in .NET.TechBash 2021 is slated for October 19-22, 2021.?? Web developmentDave Brock builds a “search-as-you-type” box in Blazor.Cody Merritt Anhorn uses localization with Blazor.Changhui Xu uploads files with Angular and .NET Web API.Mark Pahulje uses HtmlAgilityPack to get all emails from an HTML page.Jon Hilton uses local storage with Blazor.Anthony Giretti tests gRPC endpoints with gRPCurl, and also explores gRPCui.The folks at Uno write about building a single-page app in XAML and C# with WebAssembly.Marinko Spasojevic handles query strings in Blazor WebAssembly.Daniel Krzyczkowski continues building out his ASP.NET Core Web API by integrating with Azure Cosmos DB.?? The .NET platformSean Killeen describes the many flavors of .NET.Mattias Karlsson writes about his boilerplate starting point for .NET console apps.David Ramel delivers a one-stop shop for .NET 5 improvements.Sam Walpole discusses writing decoupled code with MediatR.Sourabh Shirhatti writes about diagnostics improvements with .NET 5.Mána Píchová writes about .NET 5 networking improvements.? The cloudAvanindra Paruchuri writes about migrating the Azure AD gateway to .NET Core.Johnny Reilly works with Azure Easy Auth.Muhammed Saleem works with Azure Functions.Chris Noring uses Azure Key Vault to manage secrets.Bryan Soltis posts a file to an Azure Function in 3 minutes.Damian Brady generates a GitHub Actions workflow with Visual Studio or the dotnet CLI.Thomas Ardal builds and tests multiple .NET versions with GitHub Actions.Dominique St-Amand works with integration tests using Azure Storage emulator and .NET Core in Azure DevOps.Aaron Powell uses environments for approval workflows with GitHub Actions.Damien Bowden protects legacy APIs with an ASP.NET Core YARP reverse proxy and Azure AD Auth.?? LanguagesKhalid Abuhakmeh writes about Base64 encoding with C#.Franco Tiveron writes about a developer’s C# 9 cheat sheet.Bruno Sonnino uses C# to convert XML data to JSON.Jacob E. Shore writes about his first impressions of F#.Matthew Crews writes about learning resources for F#.Mark-James McDougall writes an iRacing SDK implementation in F#.?? ToolsElton Stoneman writes about understanding Microsoft’s Docker images for .NET apps.Jon P. Smith writes about updating many-to-many relationships in EF Core 5 and above.Ruben Rios writes about a more integrated terminal experience with Visual Studio.Benjamin Day writes about tests in Visual Studio for Mac.The folks at Packt write about DAPR.Peter De Tender publishes Azure Container Instances from the Docker CLI.Nikola Zivkovic writes about linear regression with ML.NET.Patrick Smacchia writes how NDepend used Resharper to quickly refactored more than 23,000 calls to Debug.Assert().Mark Heath discusses his plans for NAudio 2.Michal Bialecki asks is Entity Framework Core fast?Jon P. Smith introduces a library to automate soft deletes in EF Core.?? XamarinLeomaris Reyes introduces UX design with Xamarin Forms.Charlin Agramonte writes about XAML naming conventions in Xamarin.Forms.Leomaris Reyes works with the Infogram in Xamarin.Forms 5.0.Rafael Veronezi previews XAML UIs.James Montemagno writes about how to integrate support emails in mobile apps with data and logs.Leomaris Reyes writes about the Xamarin.Forms File Picker.?? Design, testing, and best practicesSteve Gordon writes about how to become a better developer by asking questions.Derek Comartin says start with a monolith, not microservices.Stephen Cleary writes about durable queues.?? PodcastsScott Hanselman explores event modeling with Adam Dymitruk.At Working Code podcast, a discussion on monoliths vs. microservices.The .NET Rocks podcast checks in on IdentityServer.The .NET Core Show talks Blazor with Chris Sainty.The 6-Figure Developer podcast talks to Christos Matskas about Microsoft Identity.?? VideosThe ON.NET Show inspects application metrics with dotnet-monitor, works on change notifications with Microsoft Graph, and inspects application metrics with dotnet-monitor.Scott Hanselman shows you what happens when after you enter a URL in your browser.The ASP.NET Monsters talk about migrating their site to Azure Blob Storage..At Technology and Friends, David Giard talks to Mike Benkovich about GitHub Actions and Visual Studio.


MSBUILD : error MSB1009: Project file does not exi ...
Category: .Net 7

Error building Dot Net Core 2.2 Docker Image from a Docker File <span style="background-c ...


Views: 8821 Likes: 166
What is New in DotNet 7 (Conf 2022 Best Videos)
Category: .Net 7

Here is what I learned in the new release of .Net 7 D ...


Views: 0 Likes: 33
.NET Framework October 2023 Security and Quality Rollup Updates
.NET Framework October 2023 Security and Quality R ...

This week we released the October 2023 Security and Quality Rollup Updates for .NET Framework. Security The October Security and Quality Rollup Update does not contain any new security fixes. See September 2023 Security and Quality Rollup for the latest security updates. Quality and Reliability This release contains the following quality and reliability improvements. ASP.NET Addresses an issue with “System.ArgumentException Illegal characters in path” in some ASP.Net MVC requests. SqlClient Addresses an issue with SQL event source telemetry. Getting the Update The Security and Quality Rollup is available via Windows Update, Windows Server Update Services, and Microsoft Update Catalog. **Note** Customers that rely on Windows Update and Windows Server Update Services will automatically receive the .NET Framework version-specific updates. Advanced system administrators can also take use of the below direct Microsoft Update Catalog download links to .NET Framework-specific updates. Before applying these updates, please ensure that you carefully review the .NET Framework version applicability, to ensure that you only install updates on systems where they apply. The following table is for Windows 10, version 1507 and Windows Server 2016 versions and newer operating systems. Product Version Cumulative Update Windows 11, version 22H2 5031323 .NET Framework 3.5, 4.8.1 Catalog 5030651 Windows 11, version 21H2 5031225 .NET Framework 3.5, 4.8 Catalog 5030842 .NET Framework 3.5, 4.8.1 Catalog 5030650 Microsoft server operating system, version 22H2 5031605 .NET Framework 3.5, 4.8 Catalog 5030999 .NET Framework 3.5, 4.8.1 Catalog 5030998 Microsoft server operating system version 21H2 5031221 .NET Framework 3.5, 4.8 Catalog 5030999 .NET Framework 3.5, 4.8.1 Catalog 5030998 Windows 10, version 22H2 5031224 .NET Framework 3.5, 4.8 Catalog 5030841 .NET Framework 3.5, 4.8.1 Catalog 5030649 Windows 10, version 21H2 5031223 .NET Framework 3.5, 4.8 Catalog 5030841 .NET Framework 3.5, 4.8.1 Catalog 5030649 Windows 10 1809 (October 2018 Update) and Windows Server 2019 5031222 .NET Framework 3.5, 4.7.2 Catalog 5031005 .NET Framework 3.5, 4.8 Catalog 5031010 Windows 10 1607 (Anniversary Update) and Windows Server 2016 .NET Framework 3.5, 4.6.2, 4.7, 4.7.1, 4.7.2 Catalog 5031362 .NET Framework 4.8 Catalog 5031000 The following table is for earlier Windows and Windows Server versions. Product Version Security and Quality Rollup Windows Server 2012 5031227 .NET Framework 3.5 Catalog 5030160 .NET Framework 4.6.2, 4.7, 4.7.1, 4.7.2 Catalog 5031007 .NET Framework 4.8 Catalog 5031002 Windows Server 2012 R2 5031228 .NET Framework 3.5 Catalog 5029915 .NET Framework 4.6.2, 4.7, 4.7.1, 4.7.2 Catalog 5031008 .NET Framework 4.8 Catalog 5031003 Windows Embedded 7 and Windows Server 2008 R2 SP1 5031226 .NET Framework 3.5.1 Catalog 5029938 .NET Framework 4.6.2, 4.7, 4.7.1, 4.7.2 Catalog 5031006 .NET Framework 4.8 Catalog 5031001 Windows Server 2008 5031229 .NET Framework 2.0, 3.0 Catalog 5029937 .NET Framework 4.6.2 Catalog 5031006   Previous Monthly Rollups The last few .NET Framework Monthly updates are listed below for your convenience .NET Framework September 2023 Cumulative Update Preview .NET Framework September 2023 Security and Quality Rollup Updates .NET Framework August 2023 Cumulative Update Preview .NET Framework August 2023 Security and Quality Rollup Updates The post .NET Framework October 2023 Security and Quality Rollup Updates appeared first on .NET Blog.


Solved: Error] System.ArgumentException: Illegal c ...
Category: .Net 7

Error] System.ArgumentException Illegal characters in path MS Test when testing with Dot Net Cor ...


Views: 453 Likes: 93
Dotnet 8 publishing Self-Contained Application not ...
Category: Other

Question When I upgrade from Asp.Net 7 to Asp.Net 8, and then publishing the app as a Self-Conta ...


Views: 0 Likes: 9

Login to Continue, We will bring you back to this content 0



For peering opportunity Autonomouse System Number: AS401345 Custom Software Development at ErnesTech Email Address[email protected]