AI Assisted Development
Overview
AI has been the hot button topic for a while now and we’ve been using it for development, but personally I haven’t had the chance to really put it through its paces yet. I’ve only been able to use it for some light development and document related work. However, I recently took a vacation and had several days to myself and an itch to develop. What better time to see what it could really do.
A Dev Without a Clue
As mentioned, I’m an experienced senior engineer, but have yet to use an AI development assistant in any real capacity beyond light work. I have it setup and working in my IDE (Visual Studio), otherwise I’ll need to learn everything from scratch. I’ll be using the following. Hopefully starting from this perspective will help you learn what all will be needed as well.
- Visual Studio 2022
- CoPilot AI
- Claude Sonnet 4.5 Model
Getting Started
We’ll need a VS project to work with. I’m developing a personal project that will inventory, de-duplicate, and organize files. It’s focused on media files, but can work with any type of files. The initial version looked like this. Not terrible, but not great. It also needed a lot of heavy foundational work (e.g. logging, state persistence, parallelization centralization, locking work, configuration exposure, etc.). There’s plenty here for us to do that we can test Copilot to do everything from light work to some really heavy lifting. I won’t hold back. Anything and everything I want to do, I’ll try.

Start Light
I started initially by adding the toolbar myself before starting this CoPilot test. It had some initial buttons that were duplicates of the ones available elsewhere (e.g. New, Options, Help, etc.). However, the default sizing and look wasn’t great.
For the first set of changes, I wanted to start light. Could CoPilot and Claude Sonnet 4.5 update a forms interface including the components on the design.cs (form surface)? My first task was to update this admittedly dated interface to look more user modern and professional. I simply told CoPilot to do the following.
“Reference the #solution. Update the form #Main to provide a modern and professional style.”
It happily spit out updated Main.cs and Main.design.cs files that I reviewed and then applied using the Apply buttons. I liked the updates it made, so I setup a GitHub repository on my account for this project and made my first commit.
We eventually wound up with a toolbar that looked like this. Much better.

That represented 2 changes on 2 different days, but realistically about an hour of time. At this point the Undo, Redo, Open and Save buttons you see were not present. Those features come later as we dig deeper.
Good, But Can We Do More?
How about we add the following.
- Enterprise Grade Logging
- 2 Build-In File Preview Windows
- Beta-Mode Support (for 30 day software previews)
- Dual Settings Persistence (File & Registry)
- Test Suite
- Documentation
With this in mind I told CoPilot to stop slacking and do the following in 3 different commits.
“Refence the entire #solution. Make the following changes while keeping these goals in mind. (repeated for each change below)
Change 1
– Add Beta mode support which can be turned on/off
– Will allow 30 day usage when on
– Will store in a file and in the registry
– Will cross-check between the file and registry to ensure tamper protection
– Will allow 100 files to be processed when beta mode is on
Change 2
– Require no software licensing
– Add logging to disk for all operations
– Rotate logs every 90 days
Change 3
– Add 2 file preview panels that will allow the user to select a file from grdCatalog for each panel
– Preview panels should be to the left of grdCatalog and above/below each other
– Ensure wide file support of images, videos, text, etc. without licensing
This resulted in my second PR to master. It was a great upgrade to the project, but didn’t have the dependency injection based solution I was ultimately going to settle on. Progress though.
Before We Get Crazy
I started noticing that context, memory, and seemingly what “mood” CoPilot was in was a big issue. I would be working on moving my logging to dependency injection. Meanwhile it would be recoding half my work to call directly to my logging classes. If I didn’t catch it, back and forth we’d go between DI and direct calls. We’d loop endlessly if I didn’t see the issue and stop it. If you don’t follow this section, you’ll be battling CoPilot’s short-term memory and reference issues constantly. Let’s fix this problem.
You can create the following file in the root of your project folder to give CoPilot a helping hand.
\.github\copilot-instructions.md
You don’t even need to write it yourself. I started small and had CoPilot write it by telling CoPilot the following.
“Reference this #solution. Is there a way to guide CoPilot by writing an instructions file in my project that will tell it things like the following?
– Use dependency injection from Program.cs for logging
– Settings should be stored in AppSettings.cs and persisted in SettingsManager.cs
– Ensure adequate test coverage
– UI should have a modern and professional design
– Development should be professional, secure, and robust”
It spit out a copilot-instructions.md file which I applied using the Apply button. As I added more functionality, I had to keep coming back to CoPilot to tell it to update this file. However, since it is in the hidden .github folder, remember that CoPilot can’t see it by default. You’ll have to manually open it via File > Open > File.. browse for the file. Once it’s open in VS, CoPilot can edit it.
Updates to this file can be as simple as “Reference this #solution and update the #copilot-instructions.md file with the latest standards for this application.” Ensure you check this file anytime you see Copilot start going off the rails consistently. If it’s important, ensure it’s in this file.
Let’s Get Crazy (Plans)
Okay, it can do some pretty heavy work and now we’ve given it some context to work with. Let’s really kick the tires. My application has 3 stages (file inventory/duplicate detection/hashing, de-duplication, and file organization). The first stage is the heaviest, so I wrote it to split the original root directory in half and use 2 CPU threads to do the work. However, that’s only a small portion of the application that gets the benefit of multiple threads. Let’s extract this parallelization into its own ParallelWorkService that’s centralized and let all of the other services call into it so everyone can use parallelization.
To do this, we’re going to need proper dependency injection. I asked CoPilot to clean up logging via the following.
“Reference the #solution and ensure that all services are using logging via dependency injection.”
This clean up pass was much more successful with the copilot-instructions.md file in place. Now we’re prepped for the big push. For a change this size we want to make a plan and then execute on the plan. CoPilot can only execute so much at a time and this will change a lot. Performing the work in the scope of a plan allows Copilot to keep more context and execute on it in stages.
“Analyze this #solution. The #FileInventoryService currently uses 2 threads. Could we extract these threads into a centralized parallelization service so that all services within this #solution can request threads? Keep in mind the dependency injection and service pattern for this solution.”
Take a close look at my wording. I didn’t tell it to do the work, I asked a question. It told me that it was possible, but it wasn’t a good idea since only the FileInventoryService was using parallelization. I followed this up with the following.
“Would this answer change if my goal was to expand the de-duplication and file organization services to use parallization as well?”
The answer was then yes, the solution would benefit from parallelization services centralization. I reviewed the plan and all of the work required to implement it and told it to implement the work. For these larger changes, asking it for “how” it would be done and then asking it to “do” it, allows it to create a plan first, then execute sequentially through that plan.
After the first few files were implemented, I asked it to implement the next changes and repeated until the feature was done. Of course debugging and tests to cover the change were next.
Let’s Get Silly (Tests)
A major part of ensuring that a product works from the ground up and stays working throughout development is ensuring you have a good test suite. AI can certainly write a lot of tests and cover a lot of code quickly. My project has over 95% test coverage, but I’ve got to say getting the initial tests into a usable state is painful. For as brilliant as the code writing side is, the test writing side is sorely lacking.
When the initial set of tests are written you’ll end up with a ton of tests that look great, but just try running them. If your experience is anything like mine, you’ll get about an 80% success rate. The other 20% you’ll need to debug to determine why they fail. Oh, and don’t ask CoPilot why they won’t pass. It thinks EVERYTHING is a race condition (even at 32 threads, it rarely is).
The typical issues are related to invalid test assumptions, tests not being updated to match code changes, simply invalid code (type mismatches), hard coded values mismatching code, etc. You may have CoPilot take an initial look to fix a handful of tests, but you’ll need to individually debug the tests.
Final Thoughts
Here are some of my thoughts from this experience.
- Use a copilot-instructions.md file or CoPilot will drive you crazy.
- Manually debug your tests. CoPilot rarely finds the correct test issues.
- You can ask CoPilot to do pretty much anything. Just have a fresh change set ready, undo if necessary, and start over.
- Watch it! It’ll still run you in circles occasionally.
- Sometimes you have to use # references to show it in excruciating detail exactly what’s happening in code before it’ll “get it”
- This method is calling that method, passing this value. That variable then gets this of that type, blah, blah, blah. Step-by-step. Then CoPilot finally returns with it’s “ah-ha!” moment.
- If you’re using GitHub, create a circular work pattern to keep documentation and CoPilot up to date (context is important).
- Update code
- Update Readme.md
- Update copilot-instructions.md (remember, this has to be manually opened before updating)
- Remember that CoPilot can make these updates itself simply by referencing the #solution and #Readme.md for instance
Precision X1 Stops Working (Logo Only)
Overview
The Precision X1 application is used to configure fan speeds, monitor temperatures, adjust LED settings and more. However, I noticed that after upgrading from an EVGA RTX 2070 Super FTW3 Ultra Gaming to an EVGA RTX 3090 Super FTW3 Ultra, it wouldn’t run properly anymore.
When searching online, you’ll find a number of issues regarding Precision X1 not starting or having reduced functionality. The fixes for these range from disabling updates to adding a specific version of the Visual C++ redistributable assembly to your Windows System32 folder… all the way to an uninstall and manual clean up of every folder and registry setting associated with the product. Fortunately this problem is much easier to fix.
The Fix
Here’s how to fix this issue.
- Open the folder:
- %USERPROFILE%\AppData\Local\EVGA_Co.,_Ltd\PrecisionX_x64.exe_Url_vrvasebqwl5wesi2q3tshmshuzsvqfah\{VERSION}\
- {VERSION} = Version of Precision X1 installed
- Backup the user.config file (just in case) and then delete it.
- Start Precision X1.
That it.
Summary
Precision X1 relies on being able to reach the specific hardware points that relate to the temperature sensors, fan controllers, LED controllers, etc. which are all hardware specific. If you replace that hardware with entirely new hardware and the programmers haven’t accounted for this ability, you’re going to have issues. What EVGA should have done is put in a hardware signature verification and reconfiguration process… but obviously they didn’t.
So the issue? A hardware configuration that no longer applies is causing Precision X1 to crash. Solution? Remove the configuration so it can rebuild a new one.
WSUS Post Install Failure
Posted by Nathon in Systems Administration, WSUS on March 17, 2018
Overview
I was recently trying to install Windows Software Update Services (WSUS) on a Windows Server 2012 R2 server I have. However, the Post-Deployment Configuration task kept failing. Unfortunately the log file wasn’t a lot of help, since the error was fairly generic. In this article, I’ll walk you through resolving this issue.
The Error
When encountering this issue, you’ll see the following error in the log.
- System.Runtime.InteropServices.COMException (0x80070003): The system cannot find the path specified.
While resolving the problem, you might also encounter this error.
- CreateDefaultSubscription failed. Exception: System.Net.WebException: Unable to connect to the remote server —> System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it YOURIPADDRESS:8530
The Cause
Ultimately this problem is due to the removal of the Default Web Site in IIS. A lot of times this site is removed because it’s unnecessary or simply to clean up IIS. With WSUS v6 and above, it should no longer be necessary to have the Default Web Site, since no resources are being placed in this site anymore. However, there are apparently some vestiges of old code laying around the post-install task, because WSUS will not configure properly if the site is missing.
The Fix
1. Add Default Web Site
To fix this issue, you will need to add the Default Web Site back to IIS. Here is how you accomplish this and ensure it’s configured correctly.
- Open IIS Manager.
- Expand the server and Sites nodes.
- Right-click the Sites node and select Add Website.
- Enter the following information in the Add Website dialog and then click OK.
- Site name: Default Web Site
- Application pool: DefaultAppPool
- Physical path: C:\inetpub\wwwroot
- Binding
- Type: http
- IP address: All Unassigned
- Port: 80
- Host name: Leave Blank
- Start Website immediately: checked
- Select the new Default Web Site.
- In the right-side Actions pane, click Advanced Settings.
- Ensure the ID field has a value of 1.
- Click OK.
2. Start WSUS Administration Site
If you receive the second error shown in The Error section above, also perform the following.
- Open IIS Manager.
- Expand the server and Sites nodes.
- Select the Default Web Site.
- In the right-side Action pane, click Bindings.
- If the Type http doesn’t have a Port value of 80, do the following.
- Select Type http and click Edit.
- Change the Port value to 80.
- Click OK.
- Select the WSUS Administration site.
- In the right-side Action pane, click Start.
3. Run the Post-Deploy Configuration Again
Now that IIS is configured properly, you can kick off the Post-Install task again.
- Open Server Manager.
- Select WSUS from the left-hand pane.
- Select More Info from the error that states that post-install tasks need to be run.
- In the top list of the All Server Task Details, click the post-install link for WSUS.
- Watch the notifications in the bottom list to ensure you receive a “Configuration successfully completed” message.
Summary
This issue can be kind of daunting, given the generic errors you receive. However, this should get you through it. I hope it helps someone else. If you have any comments or questions, please leave them below.
Browser Immediately Closes When Debugging
Posted by Nathon in .NET, Development, Visual Studio on January 5, 2018
I recently ran into an issue while developing, that it looks like many others have experienced as well. A search didn’t provide a good resolution to the problem. However, I was able to fix it and with a far easier solution than many articles I’d read.
The Problem
The problem occurred when I started a debug session. It was still compiling when I noticed a capital letter in a region label that should be lower case (I know… I’m a perfectionist). I changed the letter, never really thinking about the fact that I changed it during compile time.
The compiler finished and Visual Studio kicked off a new browser instance, only to immediately close the browser, stop debugging and return to the Visual Studio IDE as if nothing had happened. In the output dialog was the following.
The program '[7760] iisexpress.exe: Program Trace' has exited with code 0 (0x0).
The program '[7348] iexplore.exe' has exited with code -1073741790 (0xc0000022).
I also checked the Windows Event Logs, but no errors were present relating to this issue.
The Reason
Various articles mentioned that this had to do with Edit and Continue functionality, various Visual Studio settings, IIS settings, app pools and a laundry list of other possibilities. However, it appears to have to do with the debugger in Visual Studio or some aspect of the build process.
I’ve heard that changing a file while in the process of debugging (with Edit and Continue enabled), deletes the original file before writing the new one. I haven’t verified this myself, but it would make sense as it relates to this issue.
The Fix
I tried some of the other proposed fixes for this issue. Many were not possible, such as copying all code over to a new project. However, knowing that it had to do with the build, I did the following.
- Start the project with debugging disabled
- Stop the project
- Start the project with debugging enabled
This seemed to resolve the issue. I was able to start and debug the project as usual after that. Something else to keep in mind is that I had also done an iisreset and was running Visual Studio in administrative mode at the time. I don’t believe those had anything to do with the solution, but I figured I’d note that anyway.
I hope this helps anyone else experiencing this issue!
Parsing Log Files in Excel
Posted by Nathon in Excel, Web Server on October 5, 2017
Overview
Sometimes I run into situations where I have an Excel file with a lot of blank rows or rows that contain changing information, that I want to remove. A common scenario for me is an Internet Information Services (IIS) log file. These don’t contain blank lines, but they have a header that repeats throughout the file, each day. Since I can’t properly convert the text into Excel columns with these present, I have to remove them somehow. However, I don’t want to hand select each row (there can be a LOT).
As you can see in the image, the IIS log header includes a few lines that contain the software, version, date and field names. Here’s how you can remove these pesky rows, even though these rows contain different text throughout the file (i.e. date & time changes).
I will show you how to replace these with blank lines and then remove the blank lines. These instructions will apply to the log file I’m currently working on, but simply customize them to work with whatever file you’re working with. The process should remain the same, even if the text you type is a little different.
Preparing Data
In the case of the IIS log file, we want to keep the titles for each column. To do that we will want the first list of column names to remain. Here’s how we’ll do that.
- Find the first line from the top where the line starts with “#Fields: “.
- Remove the left-most text up to the first field name (e.g. remove #Fields: “).
- Don’t forget any leading spaces as these will cause a problem later.
Removing Headers
- Click on the Excel header “A” at the top left of the window, just above the data.
- This will highlight all data in column A and ensure our next change only applies to this column.
- Press CTRL+H on your keyboard (or click the Find & Select down arrow from the Home ribbon, then select Replace).
- Enter #* (i.e. everything starting with #) into the Find what field.
- Ensure the Replace with field is empty.
- Click Replace All, then OK and Close to exit the Replace dialog.
Remove Blank Rows
- Ensure column A is still selected.
- Press F5 to open the Go To dialog.
- Click Special, select the Blanks radio button and click OK.
- Click the down arrow under the Delete button on the Home ribbon.
- Delete key on your keyboard won’t work.
- Select Delete Sheet Rows.
Convert the Data Into Columns
- Click the header “A” to select all of column A.
- Click Text to Columns from the Data ribbon.
- Choose the appropriate methods for parsing your data.
- In the case of an IIS log file, choose Delimited and click Next.
- Uncheck all except space and click Finish.
Summary
That’s it! You’ve now taken a difficult to work with log file and converted it into an Excel spreadsheet. From here you can apply filtering, create pivot tables, add graphs, etc. I hope this helps save you some time and frustration!
Auto-Build Windows Forms Menu From Name Space
Overview
Spanning the decade plus I’ve been a developer and before that as a systems administrator, I’ve written a seemingly endless supply of small programs to help me do different little jobs. This has ranged from little utilities I designed to iterate folders and rename, sort, etc. files (too inefficient to do by hand) to some pretty decent code generators. The problem is that most of these accidentally get deleted, eventually get lost when systems are reloaded or I forget that they exist altogether.
Well after about the 20th time writing one of these commonly used utilities I decided that I’d make myself a sort of “developers tool belt”. The point of this is to not “reinvent the wheel” constantly and to provide a reusable framework behind the scenes that I can add to other applications in the future. Since I’m obsessive about organization and cleanliness, even on my PC, I designed it to be a system tray resident application with no primary UI. Instead you will right-click the system tray icon and a menu will appear with one menu item for each utility. In turn clicking on these would bring up a small UI specific to that particular utility.
This would work, but since I was planning on writing a lot of utilities over a long period of time, I didn’t want to have to constantly update the menu as I created each tool. I got to thinking about the Windows Forms I would be creating for each utility and it dawned on me. They’re just instances of types that can be enumerated. If I could enumerate them then I could use them to generate menu items for them. The difficulty would be to store that information and instantiate it as it was needed without using up too much memory or causing performance degradation or other unforeseen issues.
Step 1 – Enumerating the Forms
The first thing I needed to do was to get a reliable method together for enumerating the forms that would represent each tool. This meant I had to segregate these forms so that I didn’t enumerate any other forms I might add to the application. To do this I moved the tool specific forms off into their own folder in the project and modify their namespace to include this folder. What I wound up with is a folder called “Forms” (original I know) and a namespace called “Dalton_Development_Tools.Forms”.
Once I segregated the forms, I went to work creating the method that would discover these forms and enumerate them. I wanted this method to be generic because I wanted to add it to my existing library for future use. So I created a method called “GetFormsContextMenuFromNameSpace”. Surprisingly it returns a ContextMenuStrip and requires a namespace in the form of a string, an Event Handler, a Windows Form and a Boolean value indicating whether an “Exit” item should be added to the end of the menu.
Once inside the method I get the types in the namespace, which I broke out into its own method (“GetTypesInNameSpace”). The code for that method is below. The first thing it does is determine that the name space provided has contents. Then it gets all of the Types in the currently executing assembly that have exist in the name space.
public static List GetTypesInNamespace(Assembly assembly, string nameSpace)
{
// Ensure the nameSpace parameter has contents.
if (nameSpace.IsNullOrWhiteSpace())
return null;
// Find and return the types in the assembly where the namespace equals the namespace
// provided (case insensitive).
return assembly.GetTypes().Where(t => String.Equals(t.Namespace, nameSpace, StringComparison.OrdinalIgnoreCase)).ToList();
}
This method returned a generic List of Type objects with one item for each Form that is in the Forms folder in the project. That is happening because I’m passing in Assembly.GetCallingAssembly() for the assembly and “Dalton_Development_Tools.Forms” for the name space.
Step 2 –
Accessing Session State in an HttpModule in MVC
Posted by Nathon in Development on February 9, 2017
Overview
HttpModules can be very useful for a lot of tasks. They are especially handy when trying to accomplish logging within a .NET web application. However, they also come with quite a few hurtles to overcome. In this article we’ll discuss some of those challenges as well as ways to get around them. In the end we will have an HttpModule which can access the session state in order to log the information it contains.
During normal development we typically place our code at a place in the life cycle of the application where everything has been setup and all the resources we need are available. However, in an HttpModule we are dealing with the entire life cycle of an ASP.NET/MVC application. Therefore as resources are setup and torn down, we could find our code having access to very little, depending on which event we register it to serve (see complete life cycle below).
ASP.NET Life Cycle
In order to get access to the session and to be able to log as much as possible, we will be concerning ourselves with 3 events within the life cycle.
- PreRequestHandlerExecute
- ProcessRequest (of IHttpHandler)
- PostRequestHandlerExecute
Generally, most of the code you write (controllers, other methods, etc.) will execute within the MvcHttpHandler, which executes during the ProcessRequest portion of the life cycle. For the purposes of getting access to the pipeline at the point at which the session is available, we will be placing our code in the PreRequestHandlerExecute method.
Creating an HttpModule
An HttpModule is simply a class which inherits from IHttpModule and which has been registered in the web.config.
- Create a new class, which we’ll call LogRequests.
- Update the class definition to inherit from IHttpModule.
public class LogRequests : IHttpModule
- Create a method to handle the module’s initialization
public void Init(HttpApplication httpApp) { } - Write a dispose method.
public void Dispose() { }
Registering HttpModule
We will now register the module in the web.config. Registering the module subscribes it to request-pipeline notifications. This allows it to fire events based on the events that occur within the pipeline. The registration process is slightly different depending on your IIS version and configuration. Using IIS 6.0 or IIS 7.0 Classic Mode allows you to customize requests for resources that are serviced by ASP.NET. However, IIS 7.0+ Integrated mode allows you to customize requests for any resources that IIS serves. This includes HTML files, graphic files and so on.
IIS 6.0 or IIS 7.0 Classic Mode
Place the following tag in the web.config file within the section shown.
<configuration> <system.web> <httpModules> <add name="LogRequests" type="YourNameSpace.LogRequests"/> </httpModules> </system.web> </configuration>
IIS 7.0 Integrated Mode
Place the following tag in the web.config file within the section shown.
<configuration> <system.webServer> <modules> <add name="LogRequests" type="YourNameSpace.LogRequests"/> </modules> </system.webServer> </configuration>
Accessing the Events
Now that we have a basic, functional HttpModule setup and registered to receive pipeline notices, let’s actually capture an event, so that we can log something. In order to capture the session we will need to have our code fire during a very specific portion of the life cycle. We will only have access from the PreRequestHandlerExecute event to the PostRequestHandlerExecute event. In this case we will be using the PreRequestHandlerExecute event.
- Create a method to contain the code that will execute when the event fires.
public void OnPreRequestHandlerExecute(Object sender, EventArgs e) { } - Add an event handler within the Init() method to register the new method to the event.
httpApp.PreRequestHandlerExecute += new EventHandler(this.OnPreRequestHandlerExecute);
- Add code within the Init() method, below the event handler, to set the session state behavior to read-only.
httpApp.Context.SetSessionStateBehavior(SessionStateBehavior.ReadOnly);
Logging Session Info
Now that the hard work is out of the way, let’s actually get access to the session so we can log it somewhere. This code will all go within the OnPreRequestHandlerExecute method we created.
- Get access to the HttpApplication.
var httpApp = (HttpApplication)sender;
- Test to be sure the information we need is present.
if (httpApp == null || httpApp.Request == null) return; - Utilize request or other information in whatever way you like.
httpApp.Request.RawUrl -- Full URL httpApp.Request.HttpMethod -- GET or POST httpApp.Request.IsAuthenticated -- Authenticated (T/F) httpApp.Request.LogonUserIdentity.AuthenticationType -- Auth Type httpApp.Request.LogonUserIdentity.Name -- User Name httpApp.Request.LogonUserIdentity.IsAnonymous -- Anonymous (T/F) httpApp.Request.LogonUserIdentity.IsGuest -- Guest (T/F) httpApp.Request.LogonUserIdentity.IsSystem -- System (T/F) httpApp.Request.IsLocal -- Localhost (T/F) httpApp.Request.IsSecureConnection -- HTTPS (T/F) httpApp.Request.UserHostName -- Host Name -- httpApp.Request.Browser.* -- Browser Info httpApp.Session.SessionID -- Session ID httpApp.Session.* -- Other Session Info
Summary
That’s it! You now have access to log application information, session information and a lot more, all from within your own HttpModule! I hope this helps others out. If you have any questions or comments, please feel free to leave a comment below.
Reference – ASP.NET Life Cycle
Our code creates an event handler for event 14 below. However, you could create handlers for whatever event you want by repeating the Access the Events section above for a different event below.
- Validate the request, which examines the information sent by the browser and determines whether it contains potentially malicious markup. For more information, see ValidateRequest and Script Exploits Overview.
- Perform URL mapping, if any URLs have been configured in the UrlMappingsSection section of the Web.config file.
- Raise the BeginRequest event.
- Raise the AuthenticateRequest event.
- Raise the PostAuthenticateRequest event.
- Raise the AuthorizeRequest event.
- Raise the PostAuthorizeRequest event.
- Raise the ResolveRequestCache event.
- Raise the PostResolveRequestCache event.
- Raise the MapRequestHandler event. An appropriate handler is selected based on the file-name extension of the requested resource. The handler can be a native-code module such as the IIS 7.0 StaticFileModule or a managed-code module such as the PageHandlerFactory class (which handles .aspx files).
- Raise the PostMapRequestHandler event.
- Raise the AcquireRequestState event.
- Raise the PostAcquireRequestState event.
- Raise the PreRequestHandlerExecute event.
- Call the ProcessRequest method (or the asynchronous version IHttpAsyncHandler.BeginProcessRequest) of the appropriate IHttpHandler class for the request. For example, if the request is for a page, the current page instance handles the request.
- Raise the PostRequestHandlerExecute event.
- Raise the ReleaseRequestState event.
- Raise the PostReleaseRequestState event.
- Perform response filtering if the Filter property is defined.
- Raise the UpdateRequestCache event.
- Raise the PostUpdateRequestCache event.
- Raise the LogRequest event.
- Raise the PostLogRequest event.
- Raise the EndRequest event.
- Raise the PreSendRequestHeaders event.
- Raise the PreSendRequestContent event.
High DPI Compatibility Fix
Posted by Nathon in Development on November 5, 2016
Overview
With today’s computers having high DPI/PPI (Dots-per-Inch/Pixels-per-Inch) screens, you can start experiencing some problems with the way certain pieces of software render things like buttons, dialog boxes, etc. Here is an example of this in CadSoft Eagle.

Although the menu appears normal (i.e. File, Edit, etc.), the toolbar icons are practically microscopic. There can also be problems with applications like Microsoft SQL Server Mangement Studio (SSMS) rendering dialog boxes so badly that you can’t read most of the information.
Partial Fixes
You can attempt to fix part of the problem with a combination of changes. Things like small window title text size can be adjusted in the Control Panel > Appearance and Personalization > Display section of the control panel. Here you can individually adjust each text area’s font size.

In order to adjust things like the desktop icon sizes up to reasonable sizes you can set an overall scaling level. Within the Display dialog shown above, you can click on the “set a custom scaling level” link in the text of the first paragraph to show the dialog on the left. Alternatively you can select the Change Display Settings link on the left to show the dialog on the right below. This allows an overall scaling that will allow you adjust more than just text.

However, none of these address the problem for programs that do not scale properly. The program mentioned in the beginning of this article (Eagle) is a perfect example of this. Even with scaling set to 250% the icons remain minuscule. So how do we make these stubborn programs usable?
Fixing Stubborn Apps
In order to fix those applications which refuse to scale properly, we’ll need to dig a little deeper. We will be instructing Windows, on a per application basis, that these programs are not DPI aware.
This fix will involve a registry change and the addition of a file to the folder that the program executes from. Although this is an easy change, if you are not comfortable with editing the registry, please do not implement this change. In either case, always backup your registry before making changes! You do not want to skip this step as a mistake in the registry could render your computer unusable!
How to Backup the Registry (MS KB322756)
https://support.microsoft.com/en-us/kb/322756
Steps
- Backup the registry using MS KB322756 link above.
- In the Search Windows box (next to Start button), type regedit and press enter.
- In the left-hand pane of the registry editor, browse to the following location.
- HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide
- In the right-hand pane, right-click an empty area and select New > DWORD (32-bit) Value.
- For name, type PreferExternalManifest and press enter.
- Double-click the new PreferExternalManifest key, select the Decimal radio button, type 1 in the value data box and click OK.
- Close the registry editor.
- Navigate to the folder that contains the executable of the program you want to fix and note the name of the executable.
- In our example the folder might be C:\Program Files (x86)\Eagle-7.4.0\bin\ and the executable would be eagle.exe.
- If you’re unsure, right-click the program icon, select properties and note the Target path in the Shortcut tab.
- Right-click an empty area in the folder and select New > Text Document.
- Name the new file the name of the program executable (e.g. eagle.exe) with .manifest as the extension (e.g. eagle.exe.manifest).
- Open the new text file in a text-only editor such as Notepad (do not use a word processor).
- Copy the text from the linked file below, paste it into your file, save the file and exit.
- The file is a .doc file due to WordPress limitations. Just rename it to .txt or open it in Notepad once downloaded to copy and paste the contents.
File: Manifest Contents
Summary
That’s it! You can now try your program out to see if it is rendering properly. I hope this helps others out! If you have any questions or comments, please leave them below and feel free to check out some of my other articles!

XML Comment on ‘X’ Has CRef Attribute That Could Not Be Resolved
Posted by Nathon in .NET on December 27, 2016
Overview
Here’s a scenario that a lot of us developers have probably faced or are still facing. You’re developing an application and you want to provide really good documentation. So, you dutifully XML document every single method, property, etc. in the project. However, you notice that when you build the project there are a number of Warnings similar to the following.
XML comment on ‘Namespace.Method()’ has cref attribute ‘System.Collections.Generic.List’ that could not be resolved.
XML comment on ‘Namespace.Method()’ has cref attribute ‘System.Collections.Generic.Dictionary’ that could not be resolved.
After double-checking the correct location of List as well as your spelling, you’re probably left scratching your head or “Googling” and reading articles. Well here’s the answer.
The Answer
The generic collections in the System.Collections.Generic namespace get the “generic” moniker from their ability to mold themselves to fit the type you’re working with. Within the definition of the generic collections this generic type is generally specified with a “<T>”. Well, the XML comment system also needs a type specifier to match up with the generic object’s definition. In XML comments we can’t use the less-than (<) or greater-than (>) characters in text so we instead use curly braces ({ and }). Below are some examples of how you specify this in the XML comments.
List
/// <summary> /// Returns things for a given Id. /// </summary> /// <param name="Id">A <see cref="System.Int32"/> containing the /// identifier to return all of the things for.</param> /// <returns>A <see cref="System.Collections.Generic.List{T}"/> /// containing all of the things. public List<string> GetThings(int Id) { }Dictionary
/// <summary> /// Returns key and things for a given Id. /// </summary> /// <param name="Id">A <see cref="System.Int32"/> containing the /// identifier to return all of the things for.</param> /// <returns>A <see cref="System.Collections.Generic.Dictionary{K,V}"/> /// containing all of the keys and things. public Dictionary<int, string> GetThings(int Id) { }In the List example, notice that in the <returns> section of the XML it shows a reference to the “System.Collections.Generic.List{T}” type. If you update all of the XML references that are throwing the error described above to have “{T}” at the end, the XML comment system will recognize it and resolve the error. If you have a Dictionary or other generic type, simply include the generic type characters appropriate to that definition. For instance the Dictionary object has a key and value so I simply put “{K,V}” after its definition.
Summary
I hope this helps you resolve those pesky little warnings you get when doing XML comments! If you liked this article, please feel free to check out my other posts. As always, please comment and share. I enjoy hearing from my readers!
Share this:
.NET, ASP.NET, C#, cref attribute, Development, error, System.Collections.Generic.List, VB, Visual Studio, XML, XML Comment, XML comment on has cref attribute that could not be resolved.
Leave a comment