{"id":47928,"date":"2023-09-26T10:05:00","date_gmt":"2023-09-26T17:05:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=47928"},"modified":"2024-12-13T14:03:47","modified_gmt":"2024-12-13T22:03:47","slug":"debugging-enhancements-in-dotnet-8","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/debugging-enhancements-in-dotnet-8\/","title":{"rendered":"Debugging Enhancements in .NET 8"},"content":{"rendered":"<p>Developers love .NET&#8217;s powerful and user-friendly debugging experience. Set a breakpoint in your IDE of choice, launch your app with the debugger attached and step through code and see the state of your .NET app.<\/p>\n<p>In .NET 8, we&#8217;re investing in improving the debugging experience of commonly used types in .NET apps. These include:<\/p>\n<ul>\n<li><code>HttpContext<\/code> and friends<\/li>\n<li><code>WebApplication<\/code><\/li>\n<li>MVC and Razor Pages<\/li>\n<li>gRPC<\/li>\n<li>Endpoint metadata<\/li>\n<li>Logging<\/li>\n<li>Configuration<\/li>\n<\/ul>\n<p>You should be able to find information about your app without having to drill down into the internals of these types. We&#8217;ve added <a href=\"https:\/\/learn.microsoft.com\/visualstudio\/debugger\/using-the-debuggerdisplay-attribute\">debug customization attributes<\/a> to display debug summaries and provide simplified debug proxies for commonly used .NET types.<\/p>\n<h2><code>HttpContext<\/code> and friends<\/h2>\n<p><code>HttpContext<\/code>, <code>HttpRequest<\/code> and <code>HttpResponse<\/code> are instantly familiar to developers building web apps with ASP.NET Core. If you want to see the state of an HTTP request, then these are the types that you&#8217;d debug.<\/p>\n<p>We&#8217;ve reviewed the properties on ASP.NET Core&#8217;s HTTP types to make them easy to use with the debugger. Viewing the request and response values, such as headers, cookies, query string, and form values, is much easier. <code>HttpRequest<\/code> and <code>HttpResponse<\/code> also now display a user-friendly summary of the type. Essential information like the HTTP request URL or the HTTP response status code is instantly visible.<\/p>\n<p>The screenshot below shows off improvements to <code>HttpContext<\/code> and associated types:<\/p>\n<p><strong>.NET 7<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/06\/httpcontext-debugging-before.png\" alt=\"ASP.NET Core debugging before\" \/><\/p>\n<p><strong>.NET 8<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/06\/httpcontext-debugging-after.png\" alt=\"ASP.NET Core debugging after\" \/><\/p>\n<p>Much better! Although some data is hidden away, nothing is lost. Select <code>Raw View<\/code> to see all fields and properties.<\/p>\n<h2>WebApplication<\/h2>\n<p><code>WebApplication<\/code> is the default way to configure and start ASP.NET Core apps in <code>Program.cs<\/code>. <code>WebApplication<\/code> has been updated to display important information such as configured endpoints, middleware, and <code>IConfiguration<\/code> values in your IDE&#8217;s debugger.<\/p>\n<p><strong>.NET 7<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/09\/webapplication-debugging-before.png\" alt=\"WebApplication debugging before\" \/><\/p>\n<p><strong>.NET 8<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/09\/webapplication-debugging-after.png\" alt=\"WebApplication debugging after\" \/><\/p>\n<p>We made similar improvements to the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/extensions\/generic-host\">.NET Generic Host<\/a>. The generic host is used to host apps that don&#8217;t have HTTP endpoints, such as Unix daemons and Windows Services.<\/p>\n<h2>MVC and Razor Pages<\/h2>\n<p>ASP.NET Core MVC and Razor Pages are popular frameworks for building web apps. Controllers, views, and Razor Pages receive debugging improvements in .NET 8.<\/p>\n<p>We identified a lot of extra information when debugging these frameworks. Types felt cluttered. In .NET 8, we reviewed each type and asked, &#8220;Does this spark joy?&#8221;. Most MVC and Razor types now work better with debugging, and non-essential types have been hidden away. The screenshots below show off improvements to MVC&#8217;s controller:<\/p>\n<p><strong>.NET 7<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/09\/controller-debugging-before.png\" alt=\"Controller debugging before\" \/><\/p>\n<p><strong>.NET 8<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/09\/controller-debugging-after.png\" alt=\"Controller debugging after\" \/><\/p>\n<p>We think you&#8217;ll agree this tidied-up output is easier to work with.<\/p>\n<h2>gRPC<\/h2>\n<p>gRPC is a high-performance library for building RPC services. The latest version of gRPC makes it easier for you to debug gRPC calls from the client. A gRPC call now includes information about its method, status, response headers, and trailers. Additional information about the request\/response and streaming depends on the <a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/grpc\/client#make-grpc-calls\">gRPC call type<\/a>. The example below is a unary call.<\/p>\n<p><strong>grpc-dotnet 2.55.0<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/09\/grpc-debugging-before.png\" alt=\"gRPC debugging before\" \/><\/p>\n<p><strong>grpc-dotnet 2.56.0<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/09\/grpc-debugging-after.png\" alt=\"gRPC debugging after\" \/><\/p>\n<p>Try these changes by updating <a href=\"https:\/\/www.nuget.org\/packages\/Grpc.Net.Client\">Grpc.Net.Client<\/a> to 2.56.0 or later.<\/p>\n<h2>Endpoint metadata<\/h2>\n<p><a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/fundamentals\/routing#endpoints\">Endpoints<\/a> are a central ASP.NET Core concept. An endpoint represents executable request-handling code. When an app starts up, the endpoints defined in the app are registered with routing. Then, routing matches requests to an endpoint when HTTP requests come into the app. Examples of endpoints include:<\/p>\n<ul>\n<li>MVC actions<\/li>\n<li>Razor Pages<\/li>\n<li>Minimal APIs<\/li>\n<li>gRPC methods<\/li>\n<\/ul>\n<p>Endpoints can have metadata, and metadata controls how the request is executed. For example, an <code>[Authorize]<\/code> attribute on an API is saved as endpoint metadata, and the <code>AuthorizationMiddleware<\/code> uses it when processing requests.<\/p>\n<p>In .NET 8, debug text has been added to common metadata. The screenshots below compare debugging <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/microsoft.aspnetcore.http.endpoint.metadata\"><code>Endpoint.Metadata<\/code><\/a> in .NET 7 and .NET 8. It&#8217;s easier to understand what metadata has been configured and how requests matched to the endpoint are processed.<\/p>\n<p><strong>.NET 7<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/09\/metadata-debugging-before.png\" alt=\"Metadata debugging before\" \/><\/p>\n<p><strong>.NET 8<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/09\/metadata-debugging-after.png\" alt=\"Metadata debugging after\" \/><\/p>\n<h2>Logging<\/h2>\n<p><a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/fundamentals\/logging\/\">Microsoft.Extensions.Logging<\/a> is a popular logging library for .NET apps and is used throughout ASP.NET Core. <code>ILogger<\/code> is used by an app to output structured logs.<\/p>\n<p><code>ILogger<\/code> was never designed for debugging. It&#8217;s a simple interface for writing logs. That design choice is immediately apparent when debugging an <code>ILogger<\/code> instance. It displays hard-to-understand data structures that are designed for performance.<\/p>\n<p>In .NET 8, it&#8217;s much easier to find out whether logging is enabled and what logging providers have been configured. <code>ILogger<\/code> displays a user-friendly list of helpful information, such as its name, configured log level, whether it is enabled, and configured logging providers.<\/p>\n<p><strong>.NET 7<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/09\/logging-debugging-before.png\" alt=\"Logging debugging before\" \/><\/p>\n<p><strong>.NET 8<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/09\/logging-debugging-after.png\" alt=\"Logging debugging after\" \/><\/p>\n<h2>Configuration<\/h2>\n<p><a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/extensions\/configuration\">Microsoft.Extensions.Configuration<\/a> is a configuration abstraction used by .NET apps and libraries. <code>IConfiguration<\/code> can load values from configuration providers, such as JSON files, environment variables, Azure Key Value, or third-party providers.<\/p>\n<p>An example of using configuration is in the ASP.NET Core templates. The <code>appsettings.json<\/code> file added by templates configures the app&#8217;s log levels:<\/p>\n<pre><code class=\"language-json\">{\r\n  \"Logging\": {\r\n    \"LogLevel\": {\r\n      \"Default\": \"Information\"\r\n    }\r\n  }\r\n}<\/code><\/pre>\n<p>Until .NET 8, figuring out an app&#8217;s configuration values could be very difficult. Configuration supports multiple providers, and providers can take precedence over each other. For example, the values in <code>appsettings.json<\/code> are always used, but they are conditionally overridden by <code>appsettings.Development.json<\/code> or <code>appsettings.Production.json<\/code>, depending on how an app is published.<\/p>\n<p>In .NET 8, debugging <code>IConfiguration<\/code> now displays a simple flat list of all configuration keys and values. Precedence is already calculated, so the configuration values you see are the values the app will use.<\/p>\n<p><strong>.NET 7<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/09\/configuration-debugging-before.png\" alt=\"Configuration debugging before\" \/><\/p>\n<p><strong>.NET 8<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/09\/configuration-debugging-after.png\" alt=\"Configuration debugging after\" \/><\/p>\n<h2>And more<\/h2>\n<p>There are too many improvements to go into detail for each one. Or even list them. But expect to see many more improvements to debugger visualizations in .NET 8:<\/p>\n<ul>\n<li>Dependency Injection<\/li>\n<li><code>ClaimsPrincipal<\/code> and <code>ClaimsIdentity<\/code><\/li>\n<li><code>StringValues<\/code> and <code>StringSegment<\/code><\/li>\n<li><code>HostString<\/code>, <code>PathString<\/code>, <code>QueryString<\/code> and <code>FragmentString<\/code><\/li>\n<li>HTTP header collections<\/li>\n<li><code>RouteValueDictionary<\/code><\/li>\n<li>ASP.NET Core MVC&#8217;s <code>ModelState<\/code><\/li>\n<\/ul>\n<h2>Try it now<\/h2>\n<p>.NET 8 debugging enhancements are available now in .NET 8 RC1. Try them today and let us know what you think:<\/p>\n<ol>\n<li>Download the latest .NET 8 release.<\/li>\n<li>Launch Visual Studio 2022 (or your preferred IDE) and create an ASP.NET Core or Worker Service app.<\/li>\n<li>Set breakpoints and hit F5 to run the app with debugging.<\/li>\n<\/ol>\n<p>Thanks for trying out .NET 8 and .NET 8 debugging enhancements!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>.NET 8 introduces debugging enhancements to many commonly used types. Check out what is new and discover how .NET debugging is better than ever.<\/p>\n","protected":false},"author":11402,"featured_media":47929,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7509,7196],"tags":[7701],"class_list":["post-47928","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-aspnetcore","category-debugging","tag-dotnet-8"],"acf":[],"blog_post_summary":"<p>.NET 8 introduces debugging enhancements to many commonly used types. Check out what is new and discover how .NET debugging is better than ever.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/47928","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/11402"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=47928"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/47928\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/47929"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=47928"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=47928"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=47928"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}