Skip to main content

Posts

Showing posts with the label ASP.NET MVC

Fixing integration test issues with Microsoft.AspNetCore.Mvc.Testing in .NET 9

When upgrading an ASP.NET Core application to .NET 9, I encountered the following error in my integration tests: System.InvalidOperationException: No application configured. Please specify an application via IWebHostBuilder.UseStartup, IWebHostBuilder.Configure, or specifying the startup assembly via StartupAssemblyKey in the web host configuration. I had updated my custom TestHost to switch from using a Startup.cs file to directly using the Program.cs file and the Minimal API approach. Therefore I added a partial Program.cs and updated the WebApplicationFactory class to use the Program.cs instead (more about this change in this post ). Here is the updated code: But this code didn’t work and resulted in the error message above. While giving the code a second look, I noticed that I was still referring to the Startup.cs that I didn't remove yet. I updated the code to use my Program.cs file instead: Doing that resulted in another error: A public method named ...

C# - Set environment in unit tests

When monitoring our RabbitMQ usage, I noticed some strange behavior. After drilling a little bit deeper in our monitoring data, I discovered that the integration tests for one of our projects were running against our production environment! Whoops!! Luckily the impact was limited but that doesn't mean we don't have to fix it. The fix Let me show you how we did it… The unit test code was using the Microsoft.AspNetCore.Mvc.Testing library to create an in-memory test host to test an API. Microsoft.AspNetCore.Mvc.Testing is part of the ASP.NET Core ecosystem and aims to simplify integration testing by providing essential tools and setup. Here is the original code: There is nothing wrong with the code itself and it makes it very easy to write and end-to-end integration test against our web app: One of the api endpoints puts messages on a RabbitMQ queue to process them later. A test instance exists but as I mentioned at the beginning of this post, instead of using th...

ASP.NET Core -Automatically add middleware through IStartupFilter

While browsing through the ASP.NET Core documentation , I accidently stumbled over the IStartupFilter interface. I had no idea what it did but it triggered my interest. Let's find out together in this post what this interface does and when it can be useful. What is IStartupFilter? IStartupFilter is an interface that allows you to intercept and modify how the application's request pipeline is built. It's particularly useful when you need to: Ensure certain middleware runs before any other middleware Add middleware consistently across multiple applications Create reusable middleware configurations Modify the order of middleware registration Here's the interface definition: How IStartupFilter Works When ASP.NET Core builds the middleware pipeline, it executes all registered IStartupFilter instances in the order they were registered. Each filter can add middleware before and after calling the next delegate, creating a wrapper around the exis...

Debugging the Smart Paste UI component

Yesterday I talked about the Smart Paste UI component which should help to automatically fill out a form using data from the user's clipboard. Although the feature worked, the result was weird as an 'of type string' was added to the filled in fields. Let’s debug the component to understand what is going (wr)on(g). We start by creating a subclass of type SmartPasteInference : We register this class in the DI container before the AddSmartComponents() : Add a breakpoint to the BuildPrompt method to inspect the default prompt and parameters. Run the application in debug mode and hit the 'Paste from clipboard button' Once the breakpoint is hit, we can see the debugger values: If we drill down in the Messages property, we see the following 2 messages: That already explains where the ‘of type string’ is coming from. It seems that Llama3 handles these values literally. Let’s try to update the generated prompt to get a better result. I took the original ...

Giving the .NET smart components a try–The Smart Paste button

Microsoft announced last month, the .NET Smart Components, an experimental set of AI-powered UI components that can be added to your .NET apps. They asked us to give these components a try and share our feedback. I already talked about: The Smart Combobox The Smart TextArea In this post I’ll focus on the last component that was introduced; the Smart Paste button. Smart Paste is an intelligent app feature that fills out forms automatically using data from the user's clipboard. You can use this with any existing form in your web app. Integrate Smart Paste in an ASP.NET Core MVC app The steps are the same as in my first post , but I’ll repeat them here. We start by creating a new ASP.NET Core MVC application. Remark: The Smart Components are supported in both Blazor and MVC/RazorPages applications. Add the SmartComponents.AspNetCore NuGet package to your project: dotnet add package --prerelease SmartComponents.AspNetCore Open your Program.cs file an...

Giving the .NET smart components a try–The Smart TextArea

Microsoft announced last month, the .NET Smart Components, an experimental set of AI-powered UI components that can be added to your .NET apps. They asked us to give these components a try and share our feedback. In a first post I tried the Smart Combobox . Now let’s have a look at the Smart TextArea component. The idea of the Smart TextArea is that it gives you a smart autocomplete that can be tailored to the specific context you want to use it in. It looks at what the user is currently typing and tries to make suggestions based on the configured context and tone. It feels quite similar to prompt engineering but with a focus on helping you typing a text faster and easier.  Here is an example use case from the documentation : Your app might allow agents to respond to customer/staff/user messages by typing free text, e.g., in a live chat system, support ticket system, CRM, bug tracker, etc. You can use Smart TextArea to help those agents be more productive, writing bet...

Giving the .NET smart components a try–The Smart Combobox

Microsoft announced last month, the .NET Smart Components, an experimental set of AI-powered UI components that can be added to your .NET apps. They asked us to give these components a try and share our feedback. And that is exactly what we are going to do in this blog post. Right now we have 3 components available: Smart Paste Smart Textarea Smart Combobox If you want a good overview of the available components, check out the video from Steve Sanderson: Although the video shows some compelling use cases for each of these components, we have to start somewhere. So in this post I’ll focus on the Smart Combobox as it doesn’t require any language model backend. Here is the main use case that Smart Combobox tries to solve: The problem with a traditional combobox is that if there are a lot of options available, it can be a challenge to select the right item from the list. With Smart Combobox,  the component uses semantic matching to find an item from the li...

ID4175–The issuer of the security token was not recognized by the IssuerNameRegistry

Yesterday I worked in close collaboration with one of my clients to renew the certificates on their ADFS server. Of course this wouldn't be an interesting post if nothing went wrong and there was nothing to learn. Changing the certificate is quite easy. First upload the certificate to your ADFS instance through the ADFS Management UI: Open Server Manager Click on “Tools”. Select “AD FS Management” from the menu. Expand “Service” node and click on “Certificates”. Click on “Set Service Communication Certificate” on the right side. Now you can activate this certificate using the following command: Set-AdfsSslCertificate -Thumbprint {thumbprint} That’s the easy part. So where did we get into trouble? After changing the certificate, some of our .NET applications started to fail with the following error message: ID4175: The issuer of the security token was not recognized by the IssuerNameRegistry. To accept security tokens from this issuer, configure the Issu...

dotnet pack issue–files without extension

To share components, layout and some general CSS and javascript between ASP.NET Core MVC projects, we are using a Razor Class Library. This Razor Class library is packaged as a NuGet package and uploaded to Azure Artifacts. One of the libraries we share using this approach is Bootstrap. Similar to other open source projects, Bootstrap has an extensionless LICENSE file explaining the exact license agreements. When you package this project using dotnet pack , the extensionless LICENSE file is transformed into a ‘LICENSE’ folder container the ‘LICENSE’ file: I have no idea why this happens but OK it works…until the moment I added this NuGet package as a dependency to another project. When I try to publish this project (using dotnet publish ) it fails with the following error message: Error MSB3025: The source file "C:\Program Files\dotnet\sdk\6.0.101\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publish.targets(237,5): C:\Users\tfsservice\packages\vlm.sofacore.web.huisstij...

Share reusable UI components through a Razor class library

One ASP.NET Core feature that I really like and most people are not aware of it existence are Razor Class libraries (RCL). With RCL you can package Razor views, pages, Razor components and view components and reuse them in different applications. I blogged about RCL before and although I really like the feature I got feedback from my development teams that the behavior was not consistent and they sometimes couldn’t get it working. I never had time to really investigate the root cause until now. So this blog post is here to explain my findings. The development environment First of all it is important to understand that the behavior of RCL is different in Development compared to other environments. When running the app that uses the RCL from build output ( dotnet run ), static web assets are enabled that allow ASP.NET Core to load static web assets from locations outside the wwwroot. This is required because ASP.NET Core will load the assets directly from the RCL NuGet location....

Url.ActionLink() is not thread-safe

I have an API that allows users to upload documents. To optimize the performance I save the documents to the database in parallel. After uploading has completed I return a list of URI's pointing to the document locations. Here is what the code looks like: As you can see in the code above, I combine a Task.WhenAll with a local function . Nothing special. However when I executed this code under high load, I started to get errors back from the API. A look at the logs, showed the following exception: Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: chunkLength at System.Text.StringBuilder.ToString()   at Microsoft.AspNetCore.Mvc.Routing.UrlHelperBase.GenerateUrl(String protocol, String host, String path)   at Microsoft.AspNetCore.Mvc.Routing.EndpointRoutingUrlHelper.Action(UrlActionContext urlActionContext)   at Microsoft.AspNetCore.Mvc.UrlHelperExtensions.ActionLink(IUrlHelper helper, String action, Stri...

Help! My IFormFile collection remains empty

Thanks to the built-in model binder feature in ASP.NET Core, uploading files is easy. You only need to specify an IFormFile as an action method parameter and the framework does all the hard work for you. All very handy and easy, until it doesn't work... Today I had an issue when I tried to upload multiple files at once. This is certainly supported and should work with any of the following collections that represent several files: IFormFileCollection IEnumerable < IFormFile > List < IFormFile > Here is a code example: Nothing wrong with the code above I would think. But unfortunately it didn’t work… To make it even stranger, although the List<IFormFile> remained empty, the uploaded files where available when I directly accessed the HttpContext and took a look at the Request.Forms.Files property. The problem turned out to be related in the way I uploaded the files. I had created a small helper library to construct the MultipartFormDataCon...

ASP.NET Core MVC model binding and nullable reference types

A few weeks ago I blogged about an issue where my breakpoint inside an ASP.NET MVC controller was never hit . The problem was caused by the built-in ModelStateInvalidFilter . What I didn’t share in that blog post is why the ModelState was invalid in the first place. Let’s see how a small change in my csproj file caused this… This is the model I was using: And this was an example I tried to send through my API: Everything worked until I made one small change. I updated my csproj file to start using nullable reference types : Now when I executed the same code it failed?! One look at the ModelState errors explained it: The FromAddress field is required. By enabling nullable reference types it handled both the ‘ ToAddress’ and ‘ FromAddress’ as required. To fix it, I had to update the DTO and enable nullability:

ASP.NET Core - Who stole my cookie?

I stumbled over a strange issue I had in ASP.NET Core. A cookie created in ASP.NET MVC didn’t show up in my requests in ASP.NET Core. This cookie was used to share some user preferences between 2 subsites in the same domain. The original cookie was created without setting a SameSite value but was also not marked as secure or httponly. I first updated the cookie generation logic to set both the Secure and HttpOnly value to true. This is not strictly required but as I’m only reading the cookie in the backend this is already a step in the right direction. Let’s now focus on the SameSite value. SameSite is an IETF draft standard designed to provide some protection against cross-site request forgery (CSRF) attacks. Cookies without SameSite header are treated as SameSite=Lax by default. If you know that we need SameSite=None to allow this cookie for cross-site usage, that should certainly be our next step. Remark: Cookies that assert SameSite=None must also be marked as Secu...

Model binding in ASP.NET Core

While converting an existing ASP.NET MVC application to ASP.NET Core I noticed it was using a custom model binder. That made me wonder how I could achieve the same thing in ASP.NET Core. In ASP.NET MVC a model binder had to implement the IModelBinder interface: To use the model binder you had to let the ASP.NET MVC framework know the existence of the custom model binder. In the original codebase we were using Unity and we created a small extension method that allowed us to register the Modelbinder: That extension method allowed us to write the following code: Let’s find out how to achieve the same result in ASP.NET Core… In ASP.NET Core you should also implement a IModelBinder interface, although the contract is different(and async): To use this custom model binder you can either create a custom ModelBinderProvider or use the ModelBinder attribute: More information: Custom Model Binding in ASP.NET Core

ASP.NET Core - Async action names

 I got into trouble when I created the following controller action in my ASP.NET Core application: This didn't work as expected but returned a 500 error stating: No route matches the supplied values.  The strange thing was that when I removed the 'async' suffix in the Action name it worked. This turned out to be a breaking change in ASP.NET Core 3.0 . Starting from ASP.NET Core 3.0, ASP.NET Core MVC removes the Async suffix from controller action names. Both routing and link generation are impacted by this new default. If you want to move back to the old behaviour, you can change it in the configuration:

ASP.NET Core–Taghelper doesn’t work in ViewComponent

Inside my ASP.NET Core application I created a custom ViewComponent that could be used to log out a user. To make my life a little bit easier I used an ASP.NET Core TagHelper   inside my component: Unfortunately this didn’t work and instead of parsing the custom tags the TagHelpers were rendered ‘as-is’ in the HTML output: To fix it I had to explicitly include the TagHelpers inside my ViewComponent using @ addTagHelper : @using ViewComponents.Logout @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

ASP.NET Core–Validate claims based on controller-action

For a CRUD style application we created some base controllers that encapsulate most of the logic. For every action create/read/update/delete a different claim applies and we would like to add an authorizationfilter to the base action methods. To handle this scenario, we created a custom authorizationfilter that uses the controllername and actionname to check for a specific claim:

Razor Class Libraries–Views not found

Last week I talked about Razor Class Libraries as a nice and easy way to package and share UI components for your ASP.NET Core MVC/Razor pages application. Inside my Razor Class Library I had some shared ViewComponents that I placed in a Shared folder. Unfortunately when trying to use these ViewComponents inside my ASP.NET Core Web application, the ViewComponents were not found?! It costed me some headaches before I discovered what I was doing wrong. It is really important that your shared View(Components) reside under a Views folder as this is where Razor will search it views by convention. You can override the convention if you want to but it is probably easier to just move everything to a Views folder like I did:

ASP.NET Core–Razor Class Libraries

A little known feature in ASP.NET Core (MVC/Razor pages) is the support for Razor Class libraries(RCL).  Through the RCL you can package and reuse UI components like View Components or Razor Components but also share full feature areas containing Razor view, controllers, models and so on… Let’s get started Open Visual Studio and choose Create a new project . Select Razor Class Library and click Next . Give the library a name and click on Create . Remark 1: To avoid a file name collision with the generated view library, ensure the library name doesn't end in .Views . Remark 2: Select Support pages and views if you need to support views. Otherwise only Razor components are supported. Now you can start adding your View Components and Razor components to your RCL. When building your RCL 2 DLL’s are created: One DLL containing all your logic One DLL containing your Razor views (ends with .Views ) You can now either reference this...