Aspnetcore 6 Download

0 views
Skip to first unread message

Semarias Alfna

unread,
Aug 5, 2024, 6:38:55 AM8/5/24
to fonlichanlo
Ihad the same error. The handler was AspNetCoreModule, code is %SystemRoot%\system32\inetsrv\aspnetcore.dll. Changing the handler to AspNetCoreModuleV2 with code %ProgramFiles%\IIS\Asp.Net Core Module\V2\aspnetcorev2.dll solved the problem.

This error can occur if the AspNetCoreModule is not installed properly in IIS on the computer that is running the Microsoft Dynamics NAV Web Server components. The AspNetCoreModule is installed with the Microsoft .NET Core Windows Server Hosting bundle. You can get this error if this has been not been fully installed or the installation has been damaged in some way.


So, I found an applicationHost.config in another server that had those AspNetCoreModule lines and updated the file on the broken server. Not sure why they were not being added by the .NET Core installation on that specific server.


There are also some cases where we will reference our end-to-end benchmarks which are public at Although we only display the last few months of data so that the page will load in a reasonable amount of time.


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 which can be faster in some cases.


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).


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.


dotnet/aspnetcore#44561 refactors the internals of response writing in Http.Sys to remove a bunch of GCHandle allocations and conveniently removes a List 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.


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.


dotnet/aspnetcore#46098 makes use of the new MemoryExtensions.Split(ReadOnlySpan source, Span 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.


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!


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.


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.


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.


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.


While the first use case is local and small, the second use case is the opposite, specifically solving the problem of non-local creation of arrays in one place and disposal of the same arrays for reuse in another place in the system. For example, imagine we are receiving live temperature data from UDP datagram messages in one Task or thread and displaying the temperature on a chart in a different Task/thread. We can use a channel to queue messages from the Task receiving UDP messages to the Task updating the temperature plot Chart. Thats ok, but to make it hum we can use an ArrayPool to avoid allocating new messages every time. The ArrayPool allows us to rent arrays at the UDP network end to fill with data when the UDP messages arrive, then we push the newly filled rented messages into the channel. At the other end we use the data in the messages for our temperature plot and simply return each message to the ArrayPool after the message is read. The arrays in this case cycle between the Pool and the channel. The ArrayPool.Shared is a good fit for this.

3a8082e126
Reply all
Reply to author
Forward
0 new messages